这几天在做一个设计,要用到MFC和opencv的结合,上网查了一下,发现这方面的知识不是很多,连一个简单的视频读入都有点麻烦,经过重重困难,终于做出来,为了给初学者少走弯路,现在给出大概流程和主要代码。
1,打开VC,建立一个工程,基于MFC的对话框。(我命名为Video)
2,设置opencv的lib。
3,找到resource的dialog,设置对话框,添加一个picture按键,一个open按钮,play按钮,exit按钮。open,play,exit的ID分别为IDC_OPEN,IDC_PLAY,IDC_EXIT.然后双击这三个按钮,添加消息处理函数。
4,在class中,右键单击VideoDlg,选中Add Window Message,添加OnTimer函数,并在其中添加如下代码:
if(IsAviFile)
{//选择播放视频
if(framepos>myvideo.m_totalframes)
{//判断视屏是否已经是最后一帧,即是否播完
framepos=0; //回到第一帧,继续播放
KillTimer(1);
}
else
{
myvideo.PlayVideo(framepos); //播放第framepos帧
framepos++; //下一帧的位置
}
}
5,在open的消息处理函数中,添加如下代码:
if(IsPlaying)
{
MessageBox("请先停止当前文件的播放","提示",0);
//GetDlgItem(IDC_STOP)->SetFocus();
return;
}
if(IsAviFile)
{//关闭先前已经打开了AVI视频文件
myvideo.CloseFile();
}
//打开视频文件
CString szFilters="Data Files (*.avi)|*.avi|All Files (*.*)|*.*||";
CFileDialog fileDlg(TRUE,NULL,"*.avi",OFN_FILEMUSTEXIST|OFN_HIDEREADONLY,szFilters,this);
if (fileDlg.DoModal()==IDOK)
{
KillTimer(1);
pwnd=GetDlgItem(IDC_STATIC1); //获取显示视频图像的控件ID
pdc =pwnd->GetDC();
hdc=pdc->GetSafeHdc(); //获取句柄
GetDlgItem(IDC_STATIC1)->GetClientRect(rect); //获取控件的RECT
if(myvideo.OpenVideo(fileDlg.GetPathName(),hdc,rect)) //构造视频播放对象
{
IsAviFile=TRUE; //当前用户选择了播放AVI视频文件
framepos=0; //第一帧播放
myvideo.PlayVideo(0); //预览第一帧图像
//初始化对话框界面
GetDlgItem(IDC_PLAY)->EnableWindow(TRUE);
}
}
6:在PLAY的函数中,添加如下代码:
IsPlaying=TRUE;
int speed=myvideo.GetPlaySpeed(); //获取视频本身的播放速度
SetTimer(1,speed,NULL); //每隔一段时间读出一帧视频图像
7:在EXIT的函数中,添加如下代码:
int user_choice=MessageBox("您确定要退出吗?","退出",1);
if(user_choice==IDOK)
{
CDialog::OnCancel();
}
9:到了这一步,没有定义上述三个函数所用到的一些变量,因此,要定义,
public:
Video myvideo; //定义播放视频类对象
int framepos; //记录播放视频帧位置
bool IsPlaying; //判断是否正在播放
bool IsPausing; //判断是否暂停中
bool IsAviFile; //判断是否是播放AVI视频文件
CRect rect;
CWnd *pwnd;
CDC *pdc;
HDC hdc;
10:还缺一个播放视频的函数功能,用一个类表示,新建一个类。在其头文件添加#include "cv.h" #include "highgui.h",还要声明,
CvvImage m_showimage; //CvvImage对象,用于显示帧到控件
IplImage *m_pframe; //获取帧
CvCapture *m_pcapture; //捕获
CString m_filepath; //文件路径
CRect m_rect; //播放区域
HDC m_hdc; //用于显示帧图像的句柄
bool m_isplay; //判断是否播放中
int m_framepos; //帧位置
int m_totalframes; //帧总数
int m_fps;
UINT m_timer; //定时器
int m_speed; //播放速度
在cpp文件中,添加如下代码:
int Video::OpenVideo(CString FilePath, HDC hdc, CRect rect)
{
CvCapture *capture;
capture=cvCaptureFromAVI(FilePath); //捕获视频
if(!capture)
{
AfxMessageBox("打开文件失败!");
return 0;
}
m_rect=rect; //获得picture控件的RECT
m_hdc=hdc; //获得picture控件的画图句柄
m_filepath=FilePath; //获得视频文件路径
m_pcapture=capture;
m_totalframes = (int)cvGetCaptureProperty(m_pcapture, CV_CAP_PROP_FRAME_COUNT); //获取视频帧总数
if(m_totalframes==0)
{
AfxMessageBox("不能打开该格式文件!");
return 0;
}
m_fps=(int)cvGetCaptureProperty(m_pcapture,CV_CAP_PROP_FPS); //帧率
return 1;
}
void Video::CloseFile()
{
if(m_pcapture)
{
cvReleaseCapture(&m_pcapture);
}
}
void Video::PlayVideo(int frame_pos)
{
if(frame_pos>m_totalframes)
{
return;
}
m_framepos=frame_pos; //播放帧开始位置
cvSetCaptureProperty(m_pcapture, CV_CAP_PROP_POS_FRAMES, (m_framepos%m_totalframes)); //设置播放帧位置
m_pframe=cvQueryFrame(m_pcapture); //获取一帧
if(m_pframe)
{
m_showimage.CopyOf(m_pframe,1);
m_showimage.DrawToHDC(m_hdc,&m_rect); //显示到控件
m_showimage.DrawToHDC(m_hdc,&m_rect); //显示到控件
}
}
int Video::GetPlaySpeed()
{
if(m_fps>0&&m_fps<1000)
{
m_speed=(int)(1000/m_fps); //每一帧多少毫秒
return m_speed;
}
return 0;
}
还有,在构造函数中要添加:
m_filepath=""; //文件路径
m_isplay=FALSE; //判断是否播放中
m_framepos=0; //帧位置
m_totalframes=0; //帧总数
m_fps=0; //帧率
m_speed=20; //播放速度,初始为20