一、运动物体轮廓椭圆拟合及中心
1 #include "opencv2/opencv.hpp"
2 #include<iostream>
3 using namespace std;
4 using namespace cv;
5
6 Mat MoveDetect(Mat frame1, Mat frame2)
7 {
8 Mat result = frame2.clone();
9 Mat gray1, gray2;
10 cvtColor(frame1, gray1, CV_BGR2GRAY);
11 cvtColor(frame2, gray2, CV_BGR2GRAY);
12
13 Mat diff;
14 absdiff(gray1, gray2, diff);
15 imshow("absdiss", diff);
16 threshold(diff, diff, 45, 255, CV_THRESH_BINARY);
17 imshow("threshold", diff);
18
19 Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
20 Mat element2 = getStructuringElement(MORPH_RECT, Size(25, 25));
21 erode(diff, diff, element);
22 imshow("erode", diff);
23
24 dilate(diff, diff, element2);
25 imshow("dilate", diff);
26
27 vector<vector<Point>> contours;
28 vector<Vec4i> hierarcy;
29 //画椭圆及中心
30 findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
31 cout<<"num="<<contours.size()<<endl;
32 vector<RotatedRect> box(contours.size());
33 for(int i=0; i<contours.size(); i++)
34 {
35 box[i] = fitEllipse(Mat(contours[i]));
36 ellipse(result, box[i], Scalar(0, 255, 0), 2, 8);
37 circle(result, box[i].center, 3, Scalar(0, 0, 255), -1, 8);
38 }
39 return result;
40 }
41
42 void main()
43 {
44 VideoCapture cap("E://man.avi");
45 if(!cap.isOpened()) //检查打开是否成功
46 return;
47 Mat frame;
48 Mat result;
49 Mat background;
50 int count=0;
51 while(1)
52 {
53 cap>>frame;
54 if(frame.empty())
55 break;
56 else{
57 count++;
58 if(count==1)
59 background = frame.clone(); //提取第一帧为背景帧
60 imshow("video", frame);
61 result = MoveDetect(background, frame);
62 imshow("result", result);
63 if(waitKey(50)==27)
64 break;
65 }
66 }
67 cap.release();
68 }
和上一篇文章代码的不同点在30-38行,天台行人视频适合用背景减法处理,自行车视频适合帧差法处理
二、滤波方法去除噪声
上篇文章中使用腐蚀膨胀消除噪声,这次使用滤波方法去除噪声
中值滤波
//二值化后使用中值滤波+膨胀
Mat element = getStructuringElement(MORPH_RECT, Size(11, 11));
medianBlur(diff, diff, 5);//中值滤波
imshow("medianBlur", diff);
dilate(diff, diff, element);
imshow("dilate", diff);
均值滤波
#include "opencv2/opencv.hpp"
#include<iostream>
using namespace std;
using namespace cv;
//int to string helper function
string intToString(int number)
{
stringstream ss;
ss << number;
return ss.str();
}
Mat MoveDetect(Mat background, Mat img)
{
Mat result = img.clone();
Mat gray1, gray2;
cvtColor(background, gray1, CV_BGR2GRAY);
cvtColor(img, gray2, CV_BGR2GRAY);
Mat diff;
absdiff(gray1, gray2, diff);
threshold(diff, diff, 20, 255, CV_THRESH_BINARY);
imshow("threshold", diff);
blur(diff, diff, Size(10, 10));//均值滤波
imshow("blur", diff);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
//drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8); //绘制轮廓
int x0=0, y0=0, w0=0, h0=0;
for(int i=0; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
x0 = boundRect[i].x; //获得第i个外接矩形的左上角的x坐标
y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
w0 = boundRect[i].width; //获得第i个外接矩形的宽度
h0 = boundRect[i].height; //获得第i个外接矩形的高度
//rectangle(result, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
circle(result, Point(x0+w0/2, y0+h0/2), 15, Scalar(0, 255, 0), 2, 8);
line(result, Point(x0+w0/2-15, y0+h0/2), Point(x0+w0/2+15, y0+h0/2), Scalar(0, 255, 0), 2, 8);
line(result, Point(x0+w0/2, y0+h0/2-10), Point(x0+w0/2, y0+h0/2+15), Scalar(0, 255, 0), 2, 8);
putText(result,"(" + intToString(x0+w0/2)+","+intToString(y0+h0/2)+")",Point(x0+w0/2+15, y0+h0/2), 1, 1,Scalar(255,0,0),2);
}
return result;
}
void main()
{
VideoCapture cap("E://ball.avi");
if(!cap.isOpened()) //检查打开是否成功
return;
Mat frame;
Mat result;
Mat background;
int count=0;
while(1)
{
cap>>frame;
if(frame.empty())
break;
else{
count++;
if(count==1)
background = frame.clone(); //提取第一帧为背景帧
imshow("video", frame);
result = MoveDetect(background, frame);
imshow("result", result);
if(waitKey(50)==27)
break;
}
}
cap.release();
}
三、轮廓筛选去除噪声(效果挺好的)
//其余代码相同
int x0=0, y0=0, w0=0, h0=0;
for(int i=0; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
x0 = boundRect[i].x; //获得第i个外接矩形的左上角的x坐标
y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
w0 = boundRect[i].width; //获得第i个外接矩形的宽度
h0 = boundRect[i].height; //获得第i个外接矩形的高度
//筛选
if(w0>30 && h0>30)
rectangle(result, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
}
四、运动轨迹绘制
#include "opencv2/opencv.hpp"
#include<iostream>
using namespace std;
using namespace cv;
Point center;
Point fre_center;//存储前一帧中心坐标
int num=0;
vector<Point> points;
Mat MoveDetect(Mat background, Mat img)
{
Mat result = img.clone();
Mat gray1, gray2;
cvtColor(background, gray1, CV_BGR2GRAY);
cvtColor(img, gray2, CV_BGR2GRAY);
Mat diff;
absdiff(gray1, gray2, diff);
imshow("absdiss", diff);
threshold(diff, diff, 45, 255, CV_THRESH_BINARY);
imshow("threshold", diff);
Mat element = getStructuringElement(MORPH_RECT, Size(1, 1));
Mat element2 = getStructuringElement(MORPH_RECT, Size(9, 9));
erode(diff, diff, element);
imshow("erode", diff);
dilate(diff, diff, element2);
imshow("dilate", diff);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
//drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8); //绘制轮廓
vector<RotatedRect> box(contours.size());
int x0=0, y0=0, w0=0, h0=0;
for(int i=0; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
x0 = boundRect[i].x; //获得第i个外接矩形的左上角的x坐标
y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
w0 = boundRect[i].width; //获得第i个外接矩形的宽度
h0 = boundRect[i].height; //获得第i个外接矩形的高度
if(w0>30 && h0>30)//筛选长宽大于30的轮廓
{
num++;
//rectangle(result, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
box[i] = fitEllipse(Mat(contours[i]));
ellipse(result, box[i], Scalar(255, 0, 0), 2, 8); //椭圆轮廓
circle(result, box[i].center, 3, Scalar(0, 0, 255), -1, 8); //画中心
center = box[i].center;//当前帧的中心坐标
points.push_back(center);//中心塞进points向量集
if(num !=1)
{
//line(result, fre_center, center, Scalar(255, 0, 0), 2, 8);
for(int j=0; j<points.size()-1; j++)
line(result, points[j], points[j+1], Scalar(0, 255, 0), 2, 8);
}
//fre_center = center;
}
}
return result;
}
void main()
{
VideoCapture cap("E://man.avi");
if(!cap.isOpened()) //检查打开是否成功
return;
Mat frame;
Mat background;
Mat result;
int count=0;
while(1)
{
cap>>frame;
if(!frame.empty())
{
count++;
if(count==1)
background = frame.clone(); //提取第一帧为背景帧
imshow("video", frame);
result = MoveDetect(background, frame);
imshow("result", result);
if(waitKey(30)==27)
break;
}
else
break;
}
cap.release();
}
五、车辆数量检测
1.帧差法检测运动目标
2.预处理:a.转灰度图,绝对值做差 b.二值化,腐蚀,中值滤波,膨胀 c.查找轮廓,筛选轮廓,绘制外接矩形,计数,输出
1 #include "opencv2/opencv.hpp"
2 #include<iostream>
3 using namespace std;
4 using namespace cv;
5
6 int CarNum = 0;
7 //int to string helper function
8 string intToString(int number)
9 {
10 //this function has a number input and string output
11 stringstream ss;
12 ss << number;
13 return ss.str();
14 }
15
16 Mat MoveDetect(Mat frame1, Mat frame2) {
17 Mat result = frame2.clone();
18 Mat gray1, gray2;
19 cvtColor(frame1, gray1, CV_BGR2GRAY);
20 cvtColor(frame2, gray2, CV_BGR2GRAY);
21
22 Mat diff;
23 absdiff(gray1, gray2, diff);
24 //imshow("absdiss", diff);
25 threshold(diff, diff, 25, 255, CV_THRESH_BINARY);
26 imshow("threshold", diff);
27
28 Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
29 Mat element2 = getStructuringElement(MORPH_RECT, Size(19, 19));
30 erode(diff, diff, element);
31 //imshow("erode", dst);
32 medianBlur(diff, diff, 3);
33 imshow("medianBlur", diff);
34 dilate(diff, diff, element2);
35 imshow("dilate", diff);
36
37 vector<vector<Point>> contours;
38 vector<Vec4i> hierarcy;
39 findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));//查找轮廓
40 vector<vector<Point>>contours_poly(contours.size());
41 vector<Rect> boundRect(contours.size()); //定义外接矩形集合
42 //drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8); //绘制轮廓
43 int x0 = 0, y0 = 0, w0 = 0, h0 = 0;
44 for (int i = 0; i<contours.size(); i++)
45 {
46 approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);//对图像轮廓点进行多边形拟合:轮廓点组成的点集,输出的多边形点集,精度(即两个轮廓点之间的距离),输出多边形是否封闭
47 boundRect[i] = boundingRect(Mat(contours_poly[i]));
48 if (boundRect[i].width>55 && boundRect[i].width<180 && boundRect[i].height>55 && boundRect[i].height<180) {//轮廓筛选
49 x0 = boundRect[i].x;
50 y0 = boundRect[i].y;
51 w0 = boundRect[i].width;
52 h0 = boundRect[i].height;
53
54 rectangle(result, Point(x0, y0), Point(x0 + w0, y0 + h0), Scalar(0, 255, 0), 2, 8, 0);
55 if ((y0 + h0 / 2 + 1) >= 138 && (y0 + h0 / 2 - 1) <= 142) {//经过这条线(区间),车辆数量+1
56 CarNum++;
57 }
58 }
59 line(result, Point(0, 140), Point(568, 140), Scalar(0, 0, 255), 1, 8);//画红线
60 Point org(0, 35);
61 putText(result, "CarNum=" + intToString(CarNum), org, CV_FONT_HERSHEY_SIMPLEX, 0.8f, Scalar(0, 255, 0), 2);
62 }
63 return result;
64 }
65
66 void main()
67 {
68 VideoCapture cap("E://2.avi");
69 if (!cap.isOpened()) //检查打开是否成功
70 return;
71 Mat frame;
72 Mat tmp;
73 Mat result;
74 int count = 0;
75 while (1)
76 {
77 cap >> frame;
78 if(frame.empty())//检查视频是否结束
79 break;
80 else{
81 count++;
82 if (count == 1)
83 result = MoveDetect(frame, frame);
84 else result = MoveDetect(tmp, frame);
85 imshow("video", frame);
86 imshow("result", result);
87 tmp = frame.clone();
88 if (waitKey(20) == 27)
89 break;
90 }
91 }
92 cap.release();
93 }