35、【opencv入门】运动物体检测(1) 一、简介 二、背景减法 三帧差法

运动物体检测顾名思义就是在视频(视频文件/摄像头获取)中检测运动物体(目标)。

OpenCV中常用的运动物体检测方法有背景减法、帧差法、光流法, 运动物体检测广泛应用于视频安全监控、车辆检测等方面。    

背景减法: 就是用原图像减去背景模型, 剩下的就是前景图像, 即运动目标

帧差法: 就是利用相邻的两帧或者三帧图像, 利用像素之间的差异性, 判断是否有运动目标     

------视频就是一帧一帧图像组成的

二、背景减法

基本步骤:

原图-背景 ---> 阈值处理 ---> 去噪声(腐蚀滤波) ---> 膨胀连通 ---> 查找轮廓 ---> 外接矩形(椭圆/圆)

【示例1】图像的处理

 1 //图像的处理
 2 #include "opencv2/opencv.hpp"
 3 using namespace cv;
 4 int main()
 5 {     
 6     Mat img1 = imread("1.bmp");
 7     Mat img2 = imread("5.bmp");
 8     imshow("img1", img1);
 9     imshow("img2", img2);
10 
11     Mat gray1, gray2;
12     cvtColor(img1, gray1, CV_BGR2GRAY);
13     cvtColor(img2, gray2, CV_BGR2GRAY);
14 
15     Mat diff;
16     absdiff(gray1, gray2, diff);
17     imshow("absdiss", diff);
18     threshold(diff, diff, 45, 255, CV_THRESH_BINARY);
19     imshow("threshold", diff);
20  
21     Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
22     Mat element2 = getStructuringElement(MORPH_RECT, Size(11, 11));
23     erode(diff, diff, element);
24     imshow("erode", diff);
25     dilate(diff, diff, element2);
26     imshow("dilate", diff);
27 
28     vector<vector<Point>> contours;  
29     vector<Vec4i> hierarcy;
30     findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
31     vector<Rect> boundRect(contours.size()); //定义外接矩形集合
32     //drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8);  //绘制轮廓
33     int x0=0, y0=0, w0=0, h0=0;
34     for(int i=0; i<contours.size(); i++)
35     {
36         boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
37         x0 = boundRect[i].x;  //获得第i个外接矩形的左上角的x坐标
38         y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
39         w0 = boundRect[i].width; //获得第i个外接矩形的宽度
40         h0 = boundRect[i].height; //获得第i个外接矩形的高度
41         rectangle(img2, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
42     }
43     imshow("result", img2);
44   
45     waitKey(0);
46     return 0;
47 }

【示例2】视频的处理

 1 //视频处理
 2 #include "opencv2/opencv.hpp"
 3 #include<iostream>
 4 
 5 using namespace std;
 6 using namespace cv;
 7 
 8 Mat MoveDetect(Mat background, Mat img)
 9 {
10     Mat result = img.clone();
11     Mat gray1, gray2;
12     cvtColor(background, gray1, CV_BGR2GRAY);
13     cvtColor(img, gray2, CV_BGR2GRAY);
14 
15     Mat diff;
16     absdiff(gray1, gray2, diff);
17     //imshow("absdiss", diff);
18     threshold(diff, diff, 45, 255, CV_THRESH_BINARY);
19     //imshow("threshold", diff);
20  
21     Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
22     Mat element2 = getStructuringElement(MORPH_RECT, Size(15, 15));
23     erode(diff, diff, element);
24     //imshow("erode", diff);
25  
26     dilate(diff, diff, element2);
27     //imshow("dilate", diff);
28 
29     vector<vector<Point>> contours;  
30     vector<Vec4i> hierarcy;
31     findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
32     vector<Rect> boundRect(contours.size()); //定义外接矩形集合
33     //drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8);  //绘制轮廓
34     int x0=0, y0=0, w0=0, h0=0;
35     for(int i=0; i<contours.size(); i++)
36     {
37         boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
38         x0 = boundRect[i].x;  //获得第i个外接矩形的左上角的x坐标
39         y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
40         w0 = boundRect[i].width; //获得第i个外接矩形的宽度
41         h0 = boundRect[i].height; //获得第i个外接矩形的高度
42         rectangle(result, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
43     }
44     return result;
45 }
46 
47 int main()
48 {     
49     VideoCapture cap("E://bike.avi");
50     if(!cap.isOpened()) //检查打开是否成功
51          return;
52     Mat frame;
53     Mat background;
54     Mat result;
55     int count=0;
56     while(1)
57     {
58         cap>>frame;
59         if(!frame.empty())
60         {
61             count++;
62             if(count==1)
63                 background = frame.clone(); //提取第一帧为背景帧
64             imshow("video", frame);
65             result = MoveDetect(background, frame);
66             imshow("result", result);
67             if(waitKey(50)==27)
68                break;
69         }
70         else
71             break;
72     }
73     cap.release();  
74     return 0;
75 }

三帧差法

 基本步骤: 相邻帧相减------阈值处理-----去除噪声(腐蚀滤波)------膨胀连通------查找轮廓------外接矩形(椭圆/圆)

【示例】

 1 //帧差法---移动物体检测
 2 #include <opencv2/opencv.hpp>
 3 #include <iostream>
 4 
 5 using namespace std;
 6 using namespace cv;
 7 
 8 int main()
 9 {     
10     VideoCapture cap("bike.avi");
11     if(!cap.isOpened()) //检查打开是否成功
12          return;
13     Mat frame;
14     Mat result;
15     Mat temp;
16     int count=0;
17     while(1)
18     {
19         cap>>frame;
20         if(!frame.empty())
21         {
22             count++;
23             if(count==1)
24                  result = MoveDetect(frame, frame);
25             else
26                  result = MoveDetect(temp, frame);
27             imshow("video", frame);
28             imshow("result", result);
29             temp = frame.clone();
30             if(waitKey(50)==27)
31                break;
32         }
33         else
34             break;
35     }
36     cap.release();  
37     return 0;
38 }