步骤:
- 利用背景消除法找到移动的物体;
- 预处理:进行中值滤波消除椒盐噪声,然后二值化再开操作;
- 寻找轮廓;
- 画出轮廓最小矩形并统计。
#include<opencv2\opencv.hpp>
using namespace cv;
using namespace std;
int main(int arc, char** argv) {
VideoCapture capture;
capture.open("vtest.avi");
namedWindow("input", CV_WINDOW_AUTOSIZE);
namedWindow("motion objects", CV_WINDOW_AUTOSIZE);
Mat frame,mogMask;
//实例化背景消除法模型
Ptr<BackgroundSubtractorMOG2>mog2 = createBackgroundSubtractorMOG2();
//定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
//定义发现的轮廓
vector<vector<Point>>contours;
//层次
vector<Vec4i>hierarchy;
int count = 0;
//定义字符数组
char numText[2];
while (capture.read(frame)) {
imshow("input", frame);
//应用混合高斯模型去除背景
mog2->apply(frame, mogMask);
//中值滤波
medianBlur(mogMask, mogMask, 3);
//得到的结果为灰度图像,对其进行二值化
threshold(mogMask, mogMask, 100, 255, THRESH_BINARY);
//开操作
morphologyEx(mogMask, mogMask, MORPH_OPEN, kernel);
//寻找最外层轮廓
findContours(mogMask, contours, hierarchy, 0, CHAIN_APPROX_SIMPLE, Point(0, 0));
count = 0;
for (int i = 0; i < contours.size(); i++) {
//drawContours(frame, contours, i, Scalar(255, 0, 0));
double area = contourArea(contours[i]);
if (area < 1000)continue;//去掉面积小于1000的轮廓
Rect selection = boundingRect(contours[i]);
if (selection.width < 30 || selection.height < 30)continue;//去掉明显不符合被检测物体形状的轮廓
count++;
rectangle(frame, selection, Scalar(0, 0, 255), 2);
//sprintf和平时我们常用的printf函数的功能很相似。sprintf函数打印到字符串中,而printf函数打印输出到屏幕上
sprintf_s(numText, "%d", count);
putText(frame, numText, Point(selection.x, selection.y), CV_FONT_NORMAL, FONT_HERSHEY_PLAIN,Scalar(0,255,0), 1);
}
imshow("motion objects", frame);
char c = waitKey(100);
if (c == 27) { break; }
}
capture.release();
waitKey(0);
return 0;
}