您的位置:首页 > 理论基础 > 计算机网络

基于OpenCV 、VS2008 MFC对话框的USB摄像头的控制和视频播放、跟踪(logitech sphere AF网络摄像头)

2010-01-18 17:29 549 查看
基于OpenCV 、VS2008 MFC对话框的USB摄像头的控制和视频播放、跟踪(logitech sphere AF网络摄像头)

 

1.opencv

2.vs2008 mfc

3.logitech sphere AF网络摄像头的pan tilt zoom控制

4.SIR粒子滤波

 

我已经做完了,总结完后上传。

 

 



 

草稿

 PTZ
(Pan, Tilt, Zoom
)摄像机跟踪指图像工作站通过对摄像头所获取的视频图像序列处理,对运动目标进行检测、分割和跟踪,将得到的目标偏离视场中心的偏差值反馈给云台,控制其全方位转动,实现摄像机对目标的同步跟踪。

 

1.    


界面设计


基于
Visual Studio 2008

MFC
技术,
在对话框GUI
界面,往里面添加若干Button
和一个Picture
控件,如图

图2.1 GUI
界面

各个控件的ID
号由Visual C++
自动产生并存放于Resource.h
文件中,比如其中一句定义:

#define IDC_ShowImg       
             
1002

定义了图片控件的ID
号,由图片控件显示图片时只需要使用如下命令:

CDC* pDC = GetDlgItem( IDC_ShowImg)->GetDC();//
获得显示控件的DC

HDC hDC = pDC->GetSafeHdc();  
//
获取HDC(
设备句柄)
来进行绘图操作

img.DrawToHDC( hDC, &rect );
//
将图片绘制到显示控件的指定区域内

同时,为了实时显示各种参数,创建了状态栏。

HWND hStatusWindow;

HWND hDlg=GetSafeHwnd();

int IDS_STATUS =1;

hStatusWindow=CreateStatusWindow(WS_CHILD|WS_VISIBLE|WS_BORDER,TEXT("
状态栏"),hDlg, IDS_STATUS);

int pint[4]={110,250,300,-1};//110,250,300
设定间隔

::SendMessage(hStatusWindow,SB_SETPARTS,4,(LPARAM)pint);

在状态栏中,将不断显示水平、垂直转动的角度和焦距变化值,这样可以使用户在使用系统的过程中得到一些关心的准确数据。

2.    


人脸检测


人脸检测方法是一种基于积分图、级联检测器和AdaBoost
算法的方法,方法框架可以分为以下三大部分



第一部分,使用Harr-llke
特征表示人脸,使用“积分图’’实现特征数值的快速计算;

第二部分,使用Adaboost
算法挑选出一些最能代表人脸的矩形特征(
弱分类器)
,按照加权投票的方式将弱分类器构造为一个强分类器:

第三部分,将训练得到的若干强分类器串联组成一个级联结构的层叠分类器,级联结构能有效地提高分类器的检测速度。

基于AdaBoost
的人脸检测在OpenCV
中的具体实现步骤如图2.2


 

图 2.2 OpenCV2.0
实现人脸检测的基本步骤

1)     

加载分类器。利用以下语句实现分类器的加载。

static CvHaarClassifierCascade* cascade = 0;

const char* cascade_name ="haarcascade_frontalface_alt.xml";

cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );

2)      

同时,0penCV
在加载的时候将分类器转化成了内部格式。加载检测图像。在本检测中,首先将3
通道8
位的彩色图转为灰度图,然后将灰度图按缩小1.3
倍。

   
cvCvtColor( img, gray, CV_BGR2GRAY );//
将彩色图转化为灰度图

cvResize( gray, small_img, CV_INTER_LINEAR );//
将灰度图缩小

3)      

检测人脸。通过以下函数实现人脸检测

vSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,

       
1.1, 2, 0/*CV_HAAR_DO_CANNY_PRUNING*/,cvSize(30, 30) );

通过以下函数得到脸部坐标:

CvRect r = (CvRect*)cvGetSeqElem( faces,0);

 

图 2.3
人脸检测效果图

3.    


基于多线程的视频文件播放


在多线程方法中,同一进程内所有线程共享惟一的进程地址空间资源,线程间共用内存空间、寄存器、进程表项等,不存在通过第三方进行信息交换的问题;而线程内部也能通过线程数据槽等方法实现各自的变量存储,所以多线程技术是并发程序设计方式中最为简单的一种,是首选工具。

在未采用多线程前,单击Capture
按钮,视频播放的过程中整个GUI
界面将失去消息响应,因为视频播放是一个死循环的过程。为了解决这个问题,本系统采用多线程技术,实现了视频播放与主程序的独立。

在Button
控件Capture
下添加了void CmymfcDlg::OnBnClickedReadimg()
按钮点击的消息响应程序,在程序中添加如下代码:

       
CreateThread(NULL,0,CaptureThread,Capture_param,0,NULL);

创建了一个线程,线程函数为C

aptureThread
,传入参数为Capture_param
。在
DWORD WINAPI CaptureThread(LPVOID pParam)
函数中,实现了每帧视频的读取和粒子滤波的循环。

4.    


基于OpenCV 2.0
的视频文件读取


OpenCV
是一种用于数字图像处理和计算机视觉的函数库。它由英特尔公司开发,是一套可免费获得的由一些C
函数和C++
类所组成的库。OpenCV
在Windows
系统及Linux
系统下都可以使用,它提供了很多标准的图像处理算法,主要用于对图像进行一些高级处理。这些函数可以直接在具体的视频开发项目中调用,通过简单编程即可完成十分复杂庞大的开发任务,具有很好的效率。

CvCapture* pCapture;

pCapture = cvCaptureFromCAM(0)
;

IplImage* ipl=NULL;

ipl = cvQueryFrame( Capture_param->plistener->pCapture );

通过以上代码实现了从摄像头读取每帧图片。由于图片控件的大小是276
×276
,需要对摄像头采集的图像进行缩放。摄像头采集的图像大小是320
×240
,上下添加黑边至320
×320,
然后进行256/320

的缩放。

cvSetImageROI( TheImage, cvRect( tlx, tly, nw, nh) );

cvResize( img, TheImage );

cvResetImageROI( TheImage );

通过OpenCV
设置感兴趣区域ROI
进行缩放,
可以很方便地实现图片以合适尺寸显示。

5.    


PTZ

摄像头的控制


在PTZ.CPP
文件中,主要通过如下函数实现摄像头的控制。

HRESULT set_mechanical_pan_relative(IAMCameraControl *pCameraControl, long value);

HRESULT set_mechanical_tilt_relative(IAMCameraControl *pCameraControl, long value);

以上两个函数,实现了摄像头的水平和垂直转动,输入参数分别为摄像头的ID
号和转动角度。

HRESULT set_digital_zoom_absolute(IAMCameraControl *pCameraControl, long value);

这个函数实现了摄像头的放大缩小倍数。

在Logitech
此款摄像头中,焦距的变化范围从50mm
到200mm
。函数传入的value
即设置的焦距值

。这样可以看到,此摄像头最大的放大倍数是4
倍。

6.    


粒子滤波程序的实现


在Button
控件track
下添加了void CmymfcDlg:: OnBnClickedTrace ()
按钮点击的消息响应程序,在程序中添加如下代码:

if(initPFTracking((PixelsInfor *)ImageSource->imageData,

                                     
&TrackLocation,

                                     
&goalFeatuerStuctAdr,

                                     
&G_MAIN_ParticlesAdr,

                                     
G_MAIN_PARNUMBER)!=0)

                  
{

                          
AfxMessageBox("SIR initialization error!");

                  
}

启动粒子滤波程序。

其中TrackLocation
为目标位置,本系统由两种方式输入。

a)     

由鼠标响应事件产生

在GUI
界面中,添加如下消息响应事件

void CmymfcDlg::OnLButtonDown(UINT nFlags, CPoint point)

void CmymfcDlg::OnLButtonUp(UINT nFlags, CPoint point)

由鼠标画框事件,记录下目标的坐标,再传给粒子滤波初始化程序。

b)   

由AdaBoost
人脸检测程序的返回值确定。

人脸检测程序可以返回检测结果,通过一定的换算后可以得到目标位置,然后传递给粒子滤波程序,实现了人脸的自动检测和跟踪。

当初始化完成后,将粒子滤波的初始化完成标志位注为真,然后每帧图像显示前调用如下函数进行持续跟踪并返回位置坐标,画框程序根据位置坐标不断进行标注。

if(oncePFTracking((PixelsInfor *)(ImageSource->imageData),

                              
Capture_param->plistener->G_MAIN_ParticlesAdr,                
              
G_MAIN_PARNUMBER,

                                     
Capture_param->plistener->goalFeatuerStuctAdr,

                                     
&Capture_param->plistener->TrackLocation)!=0)

       
{

                      
AfxMessageBox("tracking code error!");}




总结


本系统在VS2008
下开发环境下,开发出了基于MFC
对话框的人机交互界面,使用OpenCV 2.0
函数库和多线程技术,在流畅播放视频的同时,能进行基于用户操作的Logitech USB
摄像头的PTZ
控制,能自动运行基于Adaboost
的人脸检测并具有非常高的准确性,能提供两种目标输入模式的粒子滤波程序的人脸跟踪,并能根据跟踪结果对摄像头进行水平、垂直控制,使跟踪实现了水平360
,
垂直90

的跟踪效果。

本系统只是完成了水平和垂直的转动跟踪,没有使云台根据转动参数实现目标跟踪过程中的自动镜头缩放,这个是下一步需要继续深入下去的工作。

 
五 部分代码

回答一个朋友的问题

1.怎么交换数据?

在窗体初始化的时候,创建守护线程,在守护线程中不断获取图像,并通过MFC显示。通过函数调用传递参数,不会产生延时。

以下代码是Capture_param的定义

typedef struct _tag_SOCKET_LISTEN_PARAM
{
CmymfcDlg* plistener;
}SOCKETLISTENPARAM;

SOCKETLISTENPARAM *Capture_param=(SOCKETLISTENPARAM*)pParam;


以下是显示代码

void CmymfcDlg::ShowImage( IplImage* img, UINT ID )	// ID 是Picture Control控件的ID号
{
CDC* pDC = GetDlgItem( ID ) ->GetDC();		// 获得显示控件的 DC
HDC hDC = pDC ->GetSafeHdc();				// 获取 HDC(设备句柄) 来进行绘图操作
CRect rect,rect2;
((CStatic*)GetDlgItem(ID))->GetWindowRect(&rect2);
GetDlgItem(ID) ->GetClientRect( &rect );
int rw = rect.right - rect.left;			// 求出图片控件的宽和高
int rh = rect.bottom - rect.top;
int iw = img->width;						// 读取图片的宽和高
int ih = img->height;
tx = (int)(rw - iw)/2;					// 使图片的显示位置正好在控件的正中
ty = (int)(rh - ih)/2;
SetRect( rect, tx, ty, tx+iw, ty+ih );
if(TraceFlag==FALSE)
DrawFrame(img,TraceLocation);
CvvImage cimg;
cimg.CopyOf( img );		// 复制图片
cimg.DrawToHDC( hDC, &rect );				// 将图片绘制到显示控件的指定区域内
cvWaitKey(50);
ReleaseDC( pDC );
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息