Chinaunix首页 | 论坛 | 博客
  • 博客访问: 110962
  • 博文数量: 39
  • 博客积分: 2032
  • 博客等级: 大尉
  • 技术积分: 330
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-09 10:21
文章分类
文章存档

2011年(2)

2010年(22)

2009年(15)

我的朋友

分类: C/C++

2010-06-06 21:44:10

欢迎访问我的新博客(troychengspace, )

在参加腾讯校园之星大赛中做了一些手势识别的插件,其中需要使用OpenCV相关的东西,今天将它整理一下,希望对其他人能有所帮助。

首先,OpenCV 2.1似乎不能获取设想设备的数目,名称以及其它相关属性,在实际应用中很不方便,为了解决这个问题,OpenCV论坛上YuShiQi老师给出了一个风转好的CameraDS类,通过Directshow来调用摄像头(详情请见),不过,这个类只在VC++6.0编译下通过,对于VS2005、2008和2010,需要做相应的设置,如下:

1、在CameraDS.h包含头文件之上预先定义加入如下代码

#define POINTER_64 __ptr64

2、将project ->Property-> c++ ->general->Additional Include Directories 的DirectShow/Include挪到tools->options->project and solutions->vc++ Directories->include files的文件末尾就可以了,当然也可以换成绝对目录。

问题解决后,就可以在vs2005,vs2008上编译该工程了

其次,捕捉到了视频,还需要将它显示在Image控件上,这里就没有OpenCV自身所使用的UI控件那么方便了,需要自己定义Timer函数来重复调用,过程如下:

        //打开该摄像头之前,因先检查之前是否在进行图像捕捉,若有,关闭
	ReleaseCapture();
	//打开摄像头
	if(!camera.OpenCamera(sgCurSelCameraIndex,false,FRAME_WIDTH,FRAME_HEIGHT))//这里使用CameraDS中的方法打开摄像头
	{
		MessageBox(_T("打开视频设备"+sgCameraName+"失败,请检查设备状态"),_T("SmartGesture插件信息"), MB_OK | MB_ICONEXCLAMATION);
	}
	SetTimer(status,30,NULL);//关键是这里,需要自己定义Timer函数去反复读取图像并将它显示出来,处理的代码会在OnTimer函数中出现

SetTimer函数第一个参数是Timer的标识ID,也就是下面出现的nIDEvent。可以根据不同的ID调用不同的OnTimer函数,第二个参数是调用的时间间隔,单位是ms,第三个回调函数,这里在下面的OnTimer函数中定义。接下来再来看OnTimer函数:

//定时器,用于定期查询摄像头并获得相应的帧并进行处理
void SmartGestureDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	sgFrame = camera.QueryFrame();//从摄像头获得IplImage类型的图片
	//依据事件类型对捕捉的图像进行不同的处理
	switch (nIDEvent)
	{
	case SG_NORMAL://正常捕捉状态下对帧不做处理
		cvFlip(sgFrame,sgFrame,1);
		break;
	case SG_TRACING://跟踪状态
		SGTrace(sgFrame);//跟踪状态下对帧进行追踪处理
		break;
	case SG_SETTING://设置状态
		SGSet(sgFrame);//设置状态下对图像进行设置处理
		break;
	}
	//将IplImage类型的图片转换成MFC能显示的图片格式,其中sgImage的声明为:CvvImage sgImage,sgFrame的声明为IplImage*
	sgImage.CopyOf(sgFrame,3);
	//指定绘图所需的Picture控件
	HDC sgIDCPicture = (GetDlgItem(IDC_FRAME)->GetDC())->GetSafeHdc();//从MFC的界面上获取Image控件,控件ID为IDC_FRAME
	CRect rect;
	GetDlgItem(IDC_FRAME)->GetClientRect(&rect);
	//将图片显示到MFC的Picture控件上
	sgImage.DrawToHDC(sgIDCPicture,&rect);
	::ReleaseDC(this->m_hWnd,sgIDCPicture);//一定要记住释放DC,否则会造成内存泄露
	__super::OnTimer(nIDEvent);//重新调用OnTimer函数
}

另外需要注意,如果有多个状态并调用了多个OnTimer函数,在状态转变的时候,或者是重新打开摄像头的时候,一定记住要Kill掉之前的Timer,否则会造成画面的闪烁,之后导致应用假死。如果不能有效的记录Timer的ID,那就一次将所有的Timer全部Kill,然后重新调用,如下:

//退出插件之前需要释放相应的资源
void SmartGestureDlg::ReleaseCapture()
{
	for (int i = 0; i < TEMPLATE_COUNT; i++)
	{
		KillTimer(i);
	}
	camera.CloseCamera();
}

最后稍微提一下,使用CameraDS读取到的视频图像时ImlImage类型的,这个可以使用OpenCV的函数处理,在显示的时候,使用的是CvvImage类型的,需要注意,可以在类中定义一个ImlImage类型的属性用来保存视频中的每一帧图像,处理的时候,使用这个图像的副本,然后再显示回去。

这一部分基本就这些了,千万要注意内存泄露的问题,手动申请的一定要手动释放,创建局部变量的时候也要想一想是否会造成内存泄露,三思而后编码。

阅读(3929) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~