帧差法是在连续的图像序列中两个或三个相邻帧间采用基于像素的时间差分并且二值化来提取图像中的运动区域。
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//计算二值化图中白色像素点个数
double bSums(Mat src)
{
int counter = 0;
//迭代器访问像素点
Mat_<uchar>::iterator it = src.begin<uchar>();
Mat_<uchar>::iterator itend = src.end<uchar>();
for (; it != itend; ++it)
{
if ((*it)==255) counter += 1;//二值化后,像素点是0或者255
}
int size = src.cols*src.rows;
return 1.0*counter/size;
}
int main(int argc, char** argv)
{
VideoCapture capture(0);
if (!capture.isOpened())
{
cout << "No camera !\n" << endl;
return -1;
}
Mat frame;
Mat gray;
Mat gray_dilate1;
Mat gray_dilate2;
Mat gray_dilate3;
Mat background, foreground, foreground_BW;
Mat mid_filer; //中值滤波法后的照片
Mat frame_0, frame_1;//Mat m(3, 5, CV_32FC1, 1);
int num = 0;
//---------------------------------------------------------------------
while (1)
{
capture >> frame;
imshow("frame_resize", frame);
cvtColor(frame, gray, CV_RGB2GRAY);
//选择前一帧作为背景(读入第一帧时,第一帧作为背景)
if (num == 0)
{
background = gray.clone();
frame_0 = background;
}
else
{
background = frame_0;
}
absdiff(gray, background, foreground);//用帧差法求前景 做差求绝对值
imshow("foreground", foreground);
threshold(foreground, foreground_BW, 30, 255, 0);//二值化通常设置为50 255
//threshold(foreground, foreground_BW, 0, 255 ,CV_THRESH_BINARY | CV_THRESH_OTSU) ; //此处使用大津法 自适应取阈值
imshow("foreground_BW", foreground_BW);
medianBlur(foreground_BW, mid_filer, 3); //中值滤波法
double whilenum = bSums(mid_filer);
cout << "white pixel num rate:" << whilenum << endl;
//寻找最外层轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(mid_filer, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
//Mat imageContours = Mat::zeros(mid_filer.size(), CV_8UC1); //最小外接矩形画布
for (int i = 0; i<contours.size(); i++)
{
//绘制轮廓
drawContours(mid_filer, contours, i, Scalar(255), 1, 8, hierarchy);
//绘制轮廓的最小外结矩形
RotatedRect rect = minAreaRect(contours[i]);
Point2f P[4];
rect.points(P);
for (int j = 0; j <= 3; j++)
{
line(mid_filer, P[j], P[(j + 1) % 4], Scalar(255), 2);
}
}
imshow("mid_filer", mid_filer);
frame_0 = gray.clone();
num++;
char c = waitKey(33);
if (c == 27) break;
}
}