基于MFC对话框的摄像头跟踪

来源:互联网 发布:温州网络学堂登录网址 编辑:程序博客网 时间:2024/05/17 16:14

1.选取操作背景

该例子中用picture控件实现操作,代码如下:

CRect rect;
CDC *pDC;
HDC hDC;
CWnd *pwnd;CvRect selection;CvRect track_window;

bool b_flagTracking=0; char chEdit[10];int m_fameCount=0;CvVideoWriter* m_Movie;

bool b_flagProcess=0;double m_vieoProtery;bool b_flagSaveMovie=0;bool b_flagTracking=0;

IplImage *imageTrack = 0, *hsvTrack = 0, *hueTrack = 0;
IplImage *maskTrack = 0, *backprojectTrack = 0, *histimgTrack = 0;//用HSV中的Hue分量进行跟踪

int vmin = 10, vmax = 256, smin = 30;

CvHistogram *histTrack = 0;//直方图类

int hdims = 50; // 划分直方图bins的个数,越多越精确

/*选取ID为IDC_SHOWPIC作为操作平台*/

pwnd = GetDlgItem(IDC_SHOWPIC);
pwnd->MoveWindow(35,30,352,288);
pDC =pwnd->GetDC();
hDC= pDC->GetSafeHdc();//返回输出设备上下文的句柄,以备用户操作HDC
pwnd->GetClientRect(&rect);


/*读入一个位图作为该图像控件的背景*/

CDC MemDC;
CBitmap m_Bitmap1;
m_Bitmap1.LoadBitmap(IDB_BLANK);
MemDC.CreateCompatibleDC(NULL);
MemDC.SelectObject(&m_Bitmap1);

/*bitblt直接按你指定的大小输出源dc到目标dc,而strechblt会调整你源dc大小,使之适应你所指定的目标dc大小,再输出。也就是说,strechblt输出的图总是完整的,而且充满你指定的目标DC区域,而bitblt则可能输出的图是不完整的,也可能无法充满目标dc制定区域。 */
pDC->StretchBlt(rect.left,rect.top,rect.Width(),rect.Height(),&MemDC,0,0,48,48,SRCCOPY);

m_Bitmap1.DeleteObject();
MemDC.DeleteDC();
Invalidate();
2.打开摄像头,并激发WM_TIME

m_Video=cvCreateCameraCapture(0);//-1的时候不知道是参数设置的问题还是怎么了,能打开摄像头,但是显示不了图像,后用cvCaptureFromCAM(0);替代,之后可以正常运行

3.OnTimer

CvvImage m_CvvImage;IplImage* m_Frame;//Cvvimage类参考http://www.opencv.org.cn/index.php?title=CvvImage%E7%B1%BB%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C&diff=8513

m_Frame=cvQueryFrame(m_Video);//函数cvQueryFrame从摄像头或者文件中抓取一帧,然后解压并返回这一帧。

m_CvvImage.CopyOf(m_Frame,1);//将获取的m_Frame复制到当前的对象,并设定所复制的图像为单通道

if (!b_flagTracking)
{
   m_CvvImage.DrawToHDC(hDC, &rect);//绘制图像的ROI区域到DC的pDstRect, 如果图像大小和pDstRect不一致, 图像会拉伸/压缩。
   }
b_flagProcess=1;

/*显示获取图像的属性*/

/*

获得视频获取结构的属性

double cvGetCaptureProperty( CvCapture* capture, int property_id );
capture
视频获取结构。
property_id
属性标识。可以是下面之一:
CV_CAP_PROP_POS_MSEC - 影片目前位置,为毫秒数或者视频获取时间戳
CV_CAP_PROP_POS_FRAMES - 将被下一步解压/获取的帧索引,以0为起点
CV_CAP_PROP_POS_AVI_RATIO - 视频文件的相对位置(0 - 影片的开始,1 - 影片的结尾)
CV_CAP_PROP_FRAME_WIDTH - 视频流中的帧宽度
CV_CAP_PROP_FRAME_HEIGHT - 视频流中的帧高度
CV_CAP_PROP_FPS - 帧率
CV_CAP_PROP_FOURCC - 表示codec的四个字符 CV_CAP_PROP_FRAME_COUNT - 视频文件中帧的总数

函数cvGetCaptureProperty获得摄像头或者视频文件的指定属性。

译者注:有时候这个函数在cvQueryFrame被调用一次后,再调用cvGetCaptureProperty才会返回正确的数值。*/

m_vieoProtery=cvGetCaptureProperty(m_Video,CV_CAP_PROP_POS_MSEC);
itoa(m_vieoProtery,chEdit,10);//将整数转换成字符串,按十进制进行转换

SetDlgItemText(IDC_EDIT_TIME,chEdit);
m_vieoProtery=cvGetCaptureProperty(m_Video,CV_CAP_PROP_FRAME_WIDTH);
itoa(m_vieoProtery,chEdit,10);
SetDlgItemText(IDC_EDIT_FRAME_WIDTH,chEdit);
m_vieoProtery=cvGetCaptureProperty(m_Video,CV_CAP_PROP_FRAME_HEIGHT);
itoa(m_vieoProtery,chEdit,10);
SetDlgItemText(IDC_EDIT_FRAME_HEIGHT,chEdit);
m_vieoProtery=cvGetCaptureProperty(m_Video,CV_CAP_PROP_FPS);
itoa(m_vieoProtery,chEdit,10);
SetDlgItemText(IDC_EDIT_FPS,chEdit);
m_vieoProtery=cvGetCaptureProperty(m_Video,CV_CAP_PROP_FOURCC);
itoa(m_vieoProtery,chEdit,10);
SetDlgItemText(IDC_EDIT_FOURCC,chEdit);

m_fameCount++;
// m_vieoProtery=cvGetCaptureProperty(m_Video,CV_CAP_PROP_FRAME_COUNT);
itoa(m_fameCount,chEdit,10);
SetDlgItemText(IDC_EDIT_FRAME_COUNT,chEdit);

/*保存视频*/

if (b_flagSaveMovie)
{
   if (!m_Movie)
    return;  
   cvWriteFrame(m_Movie,m_Frame);
}

/*目标跟踪*/

int i, bin_w, c;
if (!b_flagTracking)
   return;

cvCopy( m_Frame, imageTrack, 0 );//拷贝m_Frame(数组)到imageTrack
cvCvtColor( imageTrack, hsvTrack, CV_BGR2HSV );// 把图像从RGB表色系转为HSV表色系,储存到hsvTrack


if( track_object )//   如果当前有需要跟踪的物体     
{
   int _vmin = vmin, _vmax = vmax;

/*

这两个函数可用于检查图像中像素的灰度是否属于某一指定范围。cvInRange()检查,src的每一个像素点是否落在lower和upper范围中。如果src的值大于或者等于lower值,并且小于upper值,那么dst中对应的对应值将被设置为0xff;否则,dst的值将被设置为0。

cvInRangeS()的原理与之完全相同,但src是与lower和upper中的一组常量值(类型CvScala)进行比较。对于这两个函数,图像src可以是任意类型;如果图像有多个通道,那么每一种通道都将被分别处理。注意,dst的尺寸和通道数必须与src一致,且必须为8位的图像。*/


   cvInRangeS( hsvTrack, cvScalar(0,smin,MIN(_vmin,_vmax),0),cvScalar(180,256,MAX(_vmin,_vmax),0), maskTrack ); //制作掩膜板,只处理像素值为H:0~180,S:smin~256,V:vmin~vmax之间的部分,初始化CvScalar資料結構,有四個純量參數輸入為double型別
cvScalar(第一個通道純量數據,第二個通道純量數據,第三個通道純量數據,第四個通道純量數據)

   cvSplit( hsvTrack, hueTrack, 0, 0, 0 ); // 取得H分量,cvSplit函数分割多通道到单通道
  
   if( track_object < 0 )//如果需要跟踪的物体还没有进行属性提取,则进行选取框类的图像属性提取
   {
    float max_val = 0.f;
    cvSetImageROI( hueTrack, selection ); // 设置原选择框,基于给定的矩形设置图像的ROI.
    cvSetImageROI( maskTrack, selection ); // 设置Mask的选择框
   
    cvCalcHist( &hueTrack, histTrack, 0, maskTrack ); // 得到选择框内且满足掩膜板内的直方图
   
    cvGetMinMaxHistValue( histTrack, 0, &max_val, 0, 0 ); //函数 cvGetMinMaxHistValue 发现最大和最小直方块以及它们的位置。任何输出变量都是可选的。在具有同样值几个极值中,返回具有最小下标索引(以字母排列顺序定)的那一个。


    cvConvertScale( histTrack->bins, histTrack->bins, max_val ? 255. / max_val : 0., 0 ); // 对直方图转为0~255 src 输入数组.
dst 输出数组
scale 比例因子.
shift 该加数被加到输入数组元素按比例缩放后得到的元素上
函数 cvConvertScale 有多个不同的目的因此就有多个同义函数(如上面的#define所示)。该函数首先对输入数组的元素进行比例缩放,然后将shift加到比例缩放后得到的各元素上,即: dst(I)=src(I)*scale + (shift,shift,...),最后可选的类型转换将结果拷贝到输出数组。

    cvResetImageROI( hueTrack ); // remove ROI
    cvResetImageROI( maskTrack );
    track_window = selection;
    track_object = 1;
   
    cvZero( histimgTrack );
    bin_w = histimgTrack->width / hdims;
   
    for( i = 0; i < hdims; i++ )
    {
     int val = cvRound(
      cvGetReal1D(histTrack->bins,i)*histimgTrack->height/255 );//函数 cvRound, cvFloor, cvCeil 用一种舍入方法将输入浮点数转换成整数。 cvRound 返回和参数最接近的整数值。 cvFloor 返回不大于参数的最大整数值。cvCeil 返回不小于参数的最小整数值。在某些体系结构中该函数 工作起来比标准 C 操作起来还要快。


     CvScalar color = hsv2rgb(i*180.f/hdims);


     cvRectangle( histimgTrack, cvPoint(i*bin_w,histimgTrack->height),
      cvPoint((i+1)*bin_w,histimgTrack->height - val),color, -1, 8, 0 );//画直方图到图像空间(根据对角线上的两点)
    }
        }
  
   cvCalcBackProject( &hueTrack, backprojectTrack, histTrack ); // 得到hue的反向投影图
  
   cvAnd( backprojectTrack, maskTrack, backprojectTrack, 0 );//得到反向投影图mask内的内容
   cvCamShift( backprojectTrack, track_window,cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),&track_comp, &track_box );//使用MeanShift算法对backproject中的内容进行搜索,返回跟踪结果
   track_window = track_comp.rect;//得到跟踪结果的矩形框
  
   if( backproject_mode )
    cvCvtColor( backprojectTrack, imageTrack, CV_GRAY2BGR ); // 显示模式
   if( imageTrack->origin )
    track_box.angle = -track_box.angle;
        cvEllipseBox( imageTrack, track_box, CV_RGB(255,0,0), 3, CV_AA, 0 );//画出跟踪结果的位置
   }

原创粉丝点击