刚刚看了 OpenCV帮助文档里面的一个“读视频文件和运动问题检测”的例程,便简单用VC6.0的MFC对话框程序做了下测试,感觉效果不错,故贴上来供和我一样的初学者做参考,做法如下(假设已经做好OpenCV头文件及lib文件等设置):
1.用VC6.0的MFC建立一个对话框程序,设工程名为 ReadVideo;
2.在对话框上添加两个按钮,一个用于打开AVI视频文件,一个用于做处理按钮,
设ID分别为: IDC_FILE_OPEN和IDC_VIDEO_PRO;对应的响应函数分别为如下:
/***************************************************
* 打开AVI文件并获取文件路径
* By Zhihai Sun 2007-09-01
****************************************************/
void CReadVideoDlg::OnFileOpen()
{
// TODO: Add your command handler code here
// 文件打开对话框
CFileDialog dlg(true,"*.avi",NULL,NULL,"*.avi|*.avi||");
if (dlg.DoModal()==IDOK)
{
strAviFilePath = dlg.GetPathName();
}else
{
return;
}
}
/***************************************************
* 根据所选择的AVI文件进行视频处理
* 滑动平均背景建模,背景差进行运动检测
* By Zhihai Sun 2007-09-01
****************************************************/
void CReadVideoDlg::OnVideoPro()
{
// TODO: Add your command handler code here
//声明IplImage指针
IplImage* pFrame = NULL;
IplImage* pFrImg = NULL;
IplImage* pBkImg = NULL;
CvMat* pFrameMat = NULL;
CvMat* pFrMat = NULL;
CvMat* pBkMat = NULL;
CvCapture* pCapture = NULL;
int nFrmNum = 0;
//打开AVI视频文件
if(strAviFilePath=="") //判断文件路径是否为空
{
MessageBox("请先选择AVI视频文件!");
return;
}else
{
if(!(pCapture = cvCaptureFromFile(strAviFilePath)))
{
MessageBox("打开AVI视频文件失败!");
return;
}
}
//创建窗口
cvNamedWindow("Video", 1);
cvNamedWindow("Background",1);
cvNamedWindow("Foreground",1);
//使窗口有序排列,窗口宽330
cvMoveWindow("Video", 30, 0);
cvMoveWindow("Background", 360, 0);
cvMoveWindow("Foreground", 690, 0);
//逐帧读取视频
while(pFrame = cvQueryFrame( pCapture ))
{
nFrmNum++;
//如果是第一帧,需要申请内存,并初始化
if(nFrmNum == 1)
{
pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1); // 存放背景图像(灰度)
pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1); // 存放中间图像(灰度)
pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
//转化成单通道图像再处理(灰度)
cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);
cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
cvConvert(pFrImg, pFrameMat);
cvConvert(pFrImg, pFrMat);
cvConvert(pFrImg, pBkMat);
}
else
{
cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); //转化成单通道图像再处理(灰度)
cvConvert(pFrImg, pFrameMat);
//高斯滤波先,以平滑图像
//cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0);
//当前帧跟背景图相减(求背景差并取绝对值)
cvAbsDiff(pFrameMat, pBkMat, pFrMat);
//二值化前景图(这里采用特定阈值进行二值化)
cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);
//进行形态学滤波,去掉噪音
cvErode(pFrImg, pFrImg, 0, 1);
cvDilate(pFrImg, pFrImg, 0, 1);
//滑动平均更新背景(求平均)
cvRunningAvg(pFrameMat, pBkMat, 0.003, 0);
//将背景转化为图像格式,用以显示
cvConvert(pBkMat, pBkImg);
// 保持原图像的旋转方向
pBkImg->origin = pFrImg->origin = pFrame->origin;
//显示图像
cvShowImage("Video", pFrame);
cvShowImage("Background", pBkImg);
cvShowImage("Foreground", pFrImg);
//如果有按键事件,则跳出循环
//此等待也为cvShowImage函数提供时间完成显示
//等待时间可以根据CPU速度调整
if( cvWaitKey(200) >= 0 )
break;
}
}
//销毁窗口
cvDestroyWindow("Video");
cvDestroyWindow("Background");
cvDestroyWindow("Foreground");
//释放图像和矩阵
cvReleaseImage(&pFrImg);
cvReleaseImage(&pBkImg);
cvReleaseMat(&pFrameMat);
cvReleaseMat(&pFrMat);
cvReleaseMat(&pBkMat);
cvReleaseCapture(&pCapture);
}
其中 strAviFilePath为在ReadVideoDlg.h声明的CReadVideoDlg类的Public成员变量即 CString strAviFilePath; // 存放所打开AVI视频文件的路径
3.编译后运行程序,并找一个合适的背景静止的AVI视频文件即可看到效果;
4.*.exe文件需和相应的dll文件放在一起。
5.运行的效果图如图1所示,从左至右依次为视频原图、背景图、运动区域二值图。
该例子的二值化阈值可以考虑用自适应更新的方式,背景模型也可以用其它更有效的方法。感觉OpenCV函数的功能还是很强大的,实现同样的效果利用OpenCV可以更节省时间,恩,性价比较高,赞!