注意事项
1)添加命名空间
using namespace cvb;
2)
// unique_ptr<IplImage, void(*)(IplImage*)> labelImg(cvCreateImage(cvSize(width, height), IPL_DEPTH_LABEL, 1),
// [](IplImage* p){ cvReleaseImage(&p); });
错误
无法从“`anonymous-namespace'::<lambda0>”转换为“void (__cdecl *const )
暂时不使用C11的语言特性
3)
需要将使用的库函数导出来,使用如下的宏定义:
__declspec(dllexport)
源码
#include <SDKDDKVer.h>
#include <stdio.h>
#include <tchar.h>
#include<iostream>
#include "cv.h"
#include "cvblob.h"
#include "highgui.h"
#include<opencv2\opencv.hpp>
#include<opencv2\video\background_segm.hpp>
using namespace cv;
using namespace cvb;
using namespace std;
//对轮廓按面积降序排序,目的是去除那些小轮廓目标
bool descSort(vector<Point> p1, vector<Point> p2) {
return contourArea(p1) > contourArea(p2);
}
void processVideo(char* videoFilename)
{
Mat frame; // current frame
Mat fgMaskMOG2; // fg mask fg mask generated by MOG2 method
Mat bgImg; // background
Ptr<BackgroundSubtractorMOG2> pMOG2 = createBackgroundSubtractorMOG2(200, 36.0, false); // MOG2 Background subtractor
while (true)
{
VideoCapture capture(videoFilename);
if (!capture.isOpened())
{
cerr << "Unable to open video file: " << videoFilename << endl;
return;
}
int width = (int)capture.get(CV_CAP_PROP_FRAME_WIDTH);
int height = (int)capture.get(CV_CAP_PROP_FRAME_HEIGHT);
// unique_ptr<IplImage, void(*)(IplImage*)> labelImg(cvCreateImage(cvSize(width, height), IPL_DEPTH_LABEL, 1),
// [](IplImage* p){ cvReleaseImage(&p); });
IplImage* labelImg = cvCreateImage(cvSize(width, height), IPL_DEPTH_LABEL, 1);
CvBlobs blobs;
CvTracks tracks;
while (true)
{
// read input data. ESC or 'q' for quitting
int key = waitKey(1);
if (key == 'q' || key == 27)
return;
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);
morphologyEx(fgMaskMOG2, fgMaskMOG2, MORPH_CLOSE, getStructuringElement(MORPH_RECT, Size(5, 5))); // fill black holes
morphologyEx(fgMaskMOG2, fgMaskMOG2, MORPH_OPEN, getStructuringElement(MORPH_RECT, Size(5, 5))); // fill white holes
imshow("morphologyEx", fgMaskMOG2);
// track
cvLabel(&IplImage(fgMaskMOG2), labelImg, blobs);
cvFilterByArea(blobs, 64, 10000);
cvUpdateTracks(blobs, tracks, 10, 90, 30);
cvRenderTracks(tracks, &IplImage(frame), &IplImage(frame));
// show
imshow("Frame", frame);
key = waitKey(30);
}
}
}
int main() {
processVideo("E:/smoky-cars/positive/大庆东路与水机路交叉口(东北)_冀BU0157_02_141502_01_3_50.wh264");
return 0;
//读入视频
VideoCapture capture("E:/smoky-cars/positive/大庆东路与水机路交叉口(东北)_冀BU0157_02_141502_01_3_50.wh264");
//定义一个Mat变量,用于存储每一帧的图像
Mat frame;
//前景
Mat mask;
//连通分量
Mat srcImage;
//结果
Mat result;
//用混合高斯模型训练背景图像
Ptr<BackgroundSubtractorMOG2> bgsubtractor = createBackgroundSubtractorMOG2();
bgsubtractor->setVarThreshold(20);
//for (int k = 0; k < 100; k++)
//{
// //读取当前帧
// capture >> frame;
// //若视频播放完成,退出循环
// if (frame.empty())
// {
// break;
// }
// bgsubtractor->apply(frame, mask, 0.2);
//}
//imshow("前景训练结果", mask);
//循环显示每一帧
while (true)
{
//读取当前帧
capture >> frame;
//若视频播放完成,退出循环
if (frame.empty())
{
break;
}
frame.copyTo(result);
//cvtColor(frame, frame, COLOR_GRAY2BGR);
bgsubtractor->apply(frame, mask, 0.2);
imshow("原视频", frame); //显示当前帧
//waitKey(30); //延时30ms
imshow("混合高斯建模", mask);
//waitKey(30);
//cvtColor(mask, mask, COLOR_GRAY2BGR);
//对前景先进行中值滤波,再进行形态学膨胀操作,以去除伪目标和连接断开的小目标
medianBlur(mask, mask, 5);
//morphologyEx(mask, mask, MORPH_DILATE, getStructuringElement(MORPH_RECT, Size(5, 5)));
//测试:先开运算再闭运算
morphologyEx(mask, mask, MORPH_CLOSE, getStructuringElement(MORPH_RECT, Size(5, 5)));
morphologyEx(mask, mask, MORPH_OPEN, getStructuringElement(MORPH_RECT, Size(5, 5)));
imshow("混合高斯建模", mask);
waitKey(30);
//拷贝
mask.copyTo(srcImage);
//各联通分量的轮廓
//外层vector的size代表了图像中轮廓的个数,里面vector的 size代表了轮廓上点的个数
vector<vector<Point>> contours;
//只获取最外轮廓,获取每个轮廓的每个像素,并相邻两个像素位置差不超过1
findContours(srcImage, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
//测试轮廓获取
imshow("轮廓获取", srcImage);
if (contours.size() < 1) continue;
//外接矩阵
Rect rct;
//对轮廓进行外接矩阵之前先对轮廓按面积降序排序,目的为了去除小目标(伪目标)
sort(contours.begin(), contours.end(), descSort);
for (int i = 0; i < contours.size(); i++)
{
//当第i个连通分量的外接矩阵面积小于最大面积的1/6,则认为是伪目标
if (contourArea(contours[i]) < contourArea(contours[0]) / 5)
break;
//包含轮廓的最小矩阵
rct = boundingRect(contours[i]);
rectangle(result, rct, Scalar(0, 255, 0), 2);
}
imshow("结果", result);
}
getchar();
return 0;
}
参考
http://blog.csdn.net/xfgryujk/article/details/61421763