本篇内容主要是对运动物体进行检测,通过使用MOG2(高斯混合模型建模)来进行物体运动前背景分离,来检测运动的物体,最后对其进行图像处理,再画出其最小外接矩形,达到对运动物体的分割与检测。具体代码如下:
#include<opencv.hpp>
#include<imgproc.hpp>
#include<highgui.hpp>
#include<cstdio>
#include<vector>
#include<iostream>
#include<opencv2/video/background_segm.hpp>
using namespace std;
using namespace cv;
int main()
{
// Current frame
Mat frame;
// Foreground mask generated by MOG2 method
Mat fgMaskMOG2;
// Background
Mat bgImg;
// MOG2 Background subtractor
Ptr<BackgroundSubtractorMOG2> pMOG2 = createBackgroundSubtractorMOG2(200, 36.0, false);
while (true)
{
VideoCapture capture("D:\\MOG2detect.mp4");
if (!capture.isOpened())
{
cerr << "Unable to open video file: " << endl;
return -1;
}
int width = (int)capture.get(CAP_PROP_FRAME_WIDTH);
int height = (int)capture.get(CAP_PROP_FRAME_HEIGHT);
while (true)
{
Point s, p;
// Read input data. Press ESC or Q to quit
int key = waitKey(1);
if (key == 'q' || key == 27)
return 0;
if (!capture.read(frame))
break;
// Update background
pMOG2->apply(frame, fgMaskMOG2);
pMOG2->getBackgroundImage(bgImg);
imshow("BG", bgImg);
imshow("Original mask", fgMaskMOG2);
// Post process
medianBlur(fgMaskMOG2, fgMaskMOG2, 5);
imshow("medianBlur", fgMaskMOG2);
// Fill black holes
morphologyEx(fgMaskMOG2, fgMaskMOG2, MORPH_CLOSE, getStructuringElement(MORPH_RECT, Size(12, 12)));
// Fill white holes
morphologyEx(fgMaskMOG2, fgMaskMOG2, MORPH_OPEN, getStructuringElement(MORPH_RECT, Size(3, 3)));
imshow("morphologyEx", fgMaskMOG2);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(fgMaskMOG2, contours, hierarchy, RETR_CCOMP , CHAIN_APPROX_NONE); //find the contours
//Find the minimum enclosing rectangle
vector<Rect> boundRect(contours.size()); //Define the set of enclosing rectangles
vector<RotatedRect> box(contours.size()); //Define the minimum set of enclosing rectangles
Point2f rect[4];
for (int i = 0; i < contours.size(); i++)
{
box[i] = minAreaRect(Mat(contours[i])); //Calculate the minimum enclosing rectangle for each contour
boundRect[i] = boundingRect(Mat(contours[i]));
//circle(frame, Point(box[i].center.x, box[i].center.y), 5, Scalar(0, 255, 0), -1, 8); //Draw center point for the minumum enclosing rectangles
box[i].points(rect); //Assign the four ends of the smallest enclosing rectangle to the rect array
//rectangle(frame, Point(boundRect[i].x, boundRect[i].y), Point(boundRect[i].x + boundRect[i].width, boundRect[i].y + boundRect[i].height), Scalar(0, 255, 0), 2, 8);
circle(frame, s, 5, Scalar(0, 255, 0), -1, 8);
for (int j = 0; j < 4; j++)
{
line(frame, rect[j], rect[(j + 1) % 4], Scalar(0, 0, 255), 2, 8); //Rraw the edge of the smallest enclosing rectangle
}
}
// Show the frame
imshow("Frame", frame);
key = waitKey(30);
}
}
}
检测效果不是很好,但是可以参考卡尔曼滤波器进行预测可以使检测效果更平滑,不会出现突变情况。接下来是检测效果:
有兴趣的可以加入卡尔曼滤波进行平滑处理,效果会更好。如果有不好的地方欢迎大家批评指正。