刚刚看了 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可以更节省时间,恩,性价比较高,赞!