一、帧差法
1.概念:
帧差法是一种通过对视频图像序列中相邻两帧作差分运算来获得运动目标轮廓的方法,它可以很好地适用于存在多个运动目标和摄像机移动的情况。它可以很好地适用于存在多个运动目标和摄像机移动的情况。 当监控场景中出现异常物体运动时,帧与帧之间会出现较为明显的差别,两帧相减,得到两帧图像亮度差的绝对值 ,判断它是否大于阈值 来分析视频或图像序列的运动特性,确定图像序列中有无物体运动。 图像序列逐帧的差分,相当于对图像序列进行了时域下的 高通滤波 。
简单理解就像是翻页动画,就像下面这样
二、进入实战——检测车辆运动
操作步骤
1.灰度处理
//灰度处理
cvtColor(forntFrame,frontGray,CV_BGR2GRAY);
cvtColor(afterFrame,afterGray,CV_BGR2GRAY);
目的:减小图片大小,提高计算机处理速度
2.帧差处理
//帧差处理
absdiff(frontGray,afterGray,diff);
目的:找到帧与帧之间的区别
原图 灰度图
3.二值化
//二值化
threshold(diff,diff,25,255,CV_THRESH_BINARY);
目的:就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果。凸显出目标的轮廓。
原图 二值化图
4.腐蚀处理
//腐蚀处理:
Mat element=cv::getStructuringElement(MORPH_RECT,Size(3,3));
erode(diff,diff,element);
目的:将目标的边缘的“毛刺”踢除掉。使目标物体更加清晰,轮廓明显。
原图 腐蚀处理图
可以看到 环境周围的“杂质”被去除了
5.膨胀处理
//膨胀处理
Mat element2=cv::getStructuringElement(MORPH_RECT,Size(20,20));
dilate(diff,diff,element2);
目的:加粗目标,更加明显
6.对动态物体进行标记(保存关键点)
//动态物体标记
vector<vector<Point>>contours;//保存关键点
findContours(diff,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0));
7.提取关键点
//提取关键点
vector<vector<Point>>contour_poly(contours.size());
vector<Rect>boundRect(contours.size());
8.最后进行绘制
int x,y,w,h;
int num=contours.size();
for(int i=0;i<num;i++)
{
approxPolyDP(Mat(contours[i]),contour_poly[i],3,true);
boundRect[i]=boundingRect(Mat(contour_poly[i]));
x=boundRect[i].x;
y=boundRect[i].y;
w=boundRect[i].width;
h=boundRect[i].height;
//绘制
rectangle(resFrame,Point(x,y),Point(x+w,y+h),Scalar(0,255,0),2);
}
完整代码:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//帧差法检测车辆
Mat moveCheck(Mat &forntFrame,Mat &afterFrame)
{
Mat frontGray,afterGray,diff;
Mat resFrame=afterFrame.clone();
//灰度处理
cvtColor(forntFrame,frontGray,CV_BGR2GRAY);
cvtColor(afterFrame,afterGray,CV_BGR2GRAY);
//帧差处理 找到帧与帧之间运动物体差异
absdiff(frontGray,afterGray,diff);
//imshow("diff",diff);
//二值化
threshold(diff,diff,25,255,CV_THRESH_BINARY);
//imshow("threashold",diff);
//腐蚀处理:
Mat element=cv::getStructuringElement(MORPH_RECT,Size(3,3));
erode(diff,diff,element);
//imshow("erode",diff);
//膨胀处理
Mat element2=cv::getStructuringElement(MORPH_RECT,Size(20,20));
dilate(diff,diff,element2);
//imshow("dilate",diff);
//动态物体标记
vector<vector<Point>>contours;//保存关键点
findContours(diff,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0));
//提取关键点
vector<vector<Point>>contour_poly(contours.size());
vector<Rect>boundRect(contours.size());
int x,y,w,h;
int num=contours.size();
for(int i=0;i<num;i++)
{
approxPolyDP(Mat(contours[i]),contour_poly[i],3,true);
boundRect[i]=boundingRect(Mat(contour_poly[i]));
x=boundRect[i].x;
y=boundRect[i].y;
w=boundRect[i].width;
h=boundRect[i].height;
//绘制
rectangle(resFrame,Point(x,y),Point(x+w,y+h),Scalar(0,255,0),2);
}
return resFrame;
}
int main(int argc, char *argv[])
{
Mat frame;
Mat temp;
Mat res;
int count=0;
VideoCapture cap("C:/Users/15123/Pictures/Camera Roll/carMove.mp4");
while(cap.read(frame))
{
count++;
if(count==1)
{
res=moveCheck(frame,frame);
}
else
{
res=moveCheck(temp,frame);
}
temp=frame.clone();
imshow("frame",frame);
imshow("res",res);
waitKey(25);
}
return 0;
}