如何利用MFC及Opencv读入摄像头并显示画面?
一般在做机器视觉项目或其他视频监控类的工程情况下,首先遇到的问题就是如何有效读入摄像头并显示,当然在opencv当中其实只用几个函数就可以解决,但是如果想显示在指定的界面,opencv就没那么方便了,本文是利用MFC制作一个简单的视频显示界面框架。如下图:
制作步骤及方法:
1、首先利用MFC应用程序向导新建一个对话框,然后在对话框中添加如上控件,两个Picture Control并更改ID为IDC_PIC_STATIC、IDC_PIC1_STATIC及三个按钮的名字。在实现过程中会用到一个文件CvvImage,因为本人使用的软件版本是Visual Studio 2013及Opencv 2.4.9,这个文件在当前的Opencv 2.4.9版本中被删除了,也不知道为什么要弃用这个。好了,这个文件网上有很多。下载好之后将文件复制到当前工程目录下,然后在当前项目界面的右边点击添加头文件CvvImage.h以及在源文件中点击添加CvvImage.cpp文件,如下图:
之后,就在OpenCameraDlg.cpp文件中添加头文件:
#include "opencv2/opencv.hpp"
#include "CvvImage.h"
以及using namespace std; using namespace cv;
2、定义全局变量:
CvCapture* Capture;
CvCapture* m_Video;
IplImage* frame;
IplImage* m_grabframe;
CRect rect;
CDC *pDC;
HDC hDC;
CWnd *pwnd;
int ImgNum = 0;
3、在对话框中右键点击打开摄像头按钮,点击添加事件响应函数一栏,然后函数名命名为On_OpenCamera
void CShowPicture_MFCDlg::On_OpenCamera()
{
// TODO: Add your command handler code here
Capture = cvCreateCameraCapture(0); //
if (Capture==0)
{
MessageBox(_T("无法连接摄像头!!!"));
return;
}
frame = cvQueryFrame(Capture); //从摄像头或者文件中抓取并返回一帧
pDC = GetDlgItem(IDC_PIC_STATIC)->GetDC();//GetDlgItem(IDC_PIC_STATIC)意思为获取显示控件的句柄(句柄就是指针),获取显示控件的DC
GetDlgItem(IDC_PIC_STATIC)->GetClientRect(&rect);
hDC = pDC->GetSafeHdc();//获取显示控件的句柄
CvvImage m_CvvImage;
m_CvvImage.CopyOf(frame, 1); //复制该帧图像
m_CvvImage.DrawToHDC(hDC, &rect); //显示到设备的矩形框内
ReleaseDC(pDC);
SetTimer(1, 25, NULL); //定时器,定时时间和帧率一致
}
右键单击对话框在类向导中选择映射消息一栏,然后双击选择WM_TIMER,如下图所示:
在其中添加响应函数代码:
void CShowPicture_MFCDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
pDC = GetDlgItem(IDC_PIC_STATIC)->GetDC();//GetDlgItem(IDC_PIC_STATIC)意思为获取显示控件的句柄(句柄就是指针),获取显示控件的DC
GetDlgItem(IDC_PIC_STATIC)->GetClientRect(&rect);
hDC = pDC->GetSafeHdc();//获取显示控件的句柄
frame = cvQueryFrame(Capture); //从摄像头或者文件中抓取并返回一帧
CvvImage m_CvvImage;
m_CvvImage.CopyOf(frame, 1); //复制该帧图像
m_CvvImage.DrawToHDC(hDC, &rect); //显示到设备的矩形框内
CDialogEx::OnTimer(nIDEvent);
}
5、添加关闭摄像头响应函数代码
在关闭摄像头按钮上右键选择添加响应函数一栏,并命名为On_CloseCamera,代码如下:
void CShowPicture_MFCDlg::On_CloseCamera()
{
// TODO: Add your command handler code here
if (!Capture)
{
MessageBox(_T("没有打开摄像头!!!"));
return;
}
cvReleaseCapture(&Capture);
pDC = GetDlgItem(IDC_PIC_STATIC)->GetDC();//GetDlgItem(IDC_PIC_STATIC)意思为获取显示控件的句柄(句柄就是指针),获取显示控件的DC
GetDlgItem(IDC_PIC_STATIC)->GetClientRect(&rect);
hDC = pDC->GetSafeHdc();//获取显示控件的句柄
frame = cvLoadImage("D:\\Documents\\Visual Studio 2013\\Projects\\beijing.jpg"); //图片读取路径可以自己设定
CvvImage m_CvvImage;
m_CvvImage.CopyOf(frame, 1); //复制该帧图像
m_CvvImage.DrawToHDC(hDC, &rect); //显示到设备的矩形框内
ReleaseDC(pDC);
}
在捕获图像按钮上右键单击选择添加事件响应函数一栏,并命名函数为On_CaptureImage,代码如下:
void CShowPicture_MFCDlg::On_CaptureImage()
{
// TODO: Add your command handler code here
//m_grabframe = cvQueryFrame(Capture);
m_grabframe = frame;
if (m_grabframe == 0)
{
MessageBox(_T("摄像头已关闭,无法捕捉图像!!!"));
return;
}
CString ImagePath=TEXT("D:\\Documents\\Visual Studio 2013\\Projects\\标定图片\\");
//CString ImagePath = _T("D:\\Documents\\Visual Studio 2013\\Projects\\标定图片\\");
if (!PathIsDirectory(ImagePath))
{
CreateDirectory(ImagePath, 0);//不存在则创建
MessageBox(_T("标定图片文件夹已创建!!!"));
return;
}
char ImagesName[100];
ImgNum = ImgNum + 1;
sprintf_s(ImagesName, "%s%.2d%s", "D:\\Documents\\Visual Studio 2013\\Projects\\标定图片\\", ImgNum, ".jpg");
IplImage * m_snap = cvCreateImage(cvGetSize(m_grabframe), m_grabframe->depth, m_grabframe->nChannels);
cvCopy(m_grabframe, m_snap, NULL);
cvSaveImage(ImagesName, m_snap); //把图像写入指定文件夹的文件中去
//以下代码是完成图像的显示过程
pDC = GetDlgItem(IDC_PIC1_STATIC)->GetDC();//GetDlgItem(IDC_PIC_STATIC)意思为获取显示控件的句柄(句柄就是指针),获取显示控件的DC
GetDlgItem(IDC_PIC1_STATIC)->GetClientRect(&rect);
hDC = pDC->GetSafeHdc();//获取显示控件的句柄
CvvImage m_CvvImage;
m_CvvImage.CopyOf(m_snap, 1); //复制该帧图像
m_CvvImage.DrawToHDC(hDC, &rect); //显示到设备环境的矩形框内
}
有什么疑问可以留言。。。谢谢!!!