OpenCV教程

在OpenCV中文论坛看到有不少帖子讲到如何在MFC下应用OpenCV进行图像和视频处理的方法,受益颇丰,主要有下面这些帖子: 

1、opencv 数据读写操作+图像噪声+ MFC下OpenCV源代码 
2、MFC中快速应用OpenCV   &   相应论坛帖子 
3、MFC+openCV对话框中显示视频 
4、如何把视频显示到MFC的picture控件上 
5、一个人脸-人眼检测例程,大家可以参考参考 
6、A step-by-step guide to the use of Microsoft Visual C++ and the Intel OpenCV library

另外还参考了于仕琪老师的《OpenCV教程-基础篇》,不过上面这些资料主要是 VC6 和 OpenCV1.0/1.1 的版本,而我使用的是 VS2008 和 OpenCV2.0,两者与之前版本相比都有很大的不同,按照论坛教程资料来做MFC下的OpenCV应用常会遇到各种各样的编程和调试问题。接下来的学习笔记将以上面的《A step-by-step guide …》为基础,总结一下VS2008 MFC下使用OpenCV2.0进行图像和视频处理的各种问题。

一、《OpenCV教程-基础篇》2.8节中的问题

1、P27初始化代码ROI值不为0的bug

 

      IplImage* Temp = cvCreateImage(ImgSize, IPL_DEPTH_8U, 1); // 创建8U单通道图像来缓存RGB图的各通道子图;

      int h,w;
      float dx = (Temp->width / 256.0f);    // 将图像按宽度作256等分

      // 复制数据到IPL的蓝色通道
      for(w = 0; w < Temp->width; w++)
         for(h = 0;h < Temp->height; h++)
         {
            // 复制数据到IPL
            Temp->imageData[Temp->height * w + h] = (char)(w/dx); 
            // 单通道图像每一列像素的像素值等于(所在列/总列数)*256.0f
            // 其效果是使单通道图像显示为从上到下由黑到白的灰度渐变效果
         }
         /*
         函数 cvSetImageCOI 基于给定的值设置感兴趣的通道。
         值 0 意味着所有的通道都被选定, 1 意味着第一个通道被选定等等。
         如果 ROI 是 NULL 并且COI!= 0, ROI 被分配. 然而大多数的 OpenCV 函数不支持 COI, 
         对于这种状况当处理分离图像/矩阵通道时,可以拷贝(通过 cvCopy 或cvSplit) 通道来分离图像/矩阵,
         处理后如果需要可再拷贝(通过cvCopy 或 cvCvtPlaneToPix)回来.
         */
         cvSetImageCOI(TheImage,1);    // 选择TheImage的蓝色通道
         cvCopy(Temp,TheImage);        // 复制数据到TheImage的蓝色通道

      // 复制数据到IPL的绿色通道
      for(w = 0; w < Temp->width; w++)
         for(h = 0;h < Temp->height; h++)
         {
            // 复制数据到IPL
            Temp->imageData[Temp->height * w + h] = (char)(255-w/dx);
            // 用255去减w/dx,则三个通道子图合在一起会呈现出从上到下由绿变紫的彩色渐变效果
            // 如果也同红绿通道一样只用 w/dx,则最终是呈现由黑到白的灰度渐变
         }
         cvSetImageCOI(TheImage,2);    // 选择TheImage的绿色通道
         cvCopy(Temp,TheImage);        // 复制数据到TheImage的绿色通道

      // 复制数据到IPL的红色通道
      for(w = 0; w < Temp->width; w++)
         for(h = 0;h < Temp->height; h++)
         {
            // 复制数据到IPL
            Temp->imageData[Temp->height * w + h] = (char)(w/dx);//??
         }
         cvSetImageCOI(TheImage,3);    //选择TheImage的红色通道
         cvCopy(Temp,TheImage);        //复制数据到TheImage的红色通道

      cvReleaseImage(&Temp);        //释放Temp占用的内存空间

 

不过上述代码在运行之后,ROI的值不为0,这应该是一个bug,如何处理?

2、P34 cvCopy 使得运行出错的问题

P34执行Canny边缘检测的代码:

void MyIplClass::ProcessIpl(IplImage* ipl)
{
    IplImage *gray = 0, *edge = 0;
    gray = cvCreateImage( cvSize(IMAGE_WIDTH, IMAGE_HEIGHT), IPL_DEPTH_8U, 1 );
    edge = cvCreateImage( cvSize(IMAGE_WIDTH, IMAGE_HEIGHT), IPL_DEPTH_8U, 1 );
    cvCvtColor( ipl, gray, CV_BGR2GRAY );
    cvCanny( gray, edge, 30, 100, 3 );
    cvCvtColor( edge, ipl, CV_GRAY2BGR );
    // save result
    cvCopyImage( ipl, m_Ipl );

    cvReleaseImage( &gray );
    cvReleaseImage( &edge );
}

其中的 cvCopyImage( ipl, m_Ipl ) 是无法执行的,因为经过前3行的颜色转换处理后, ipl 和 m_ipl 的ROI的区域已经不一样。这需要重设 ipl 的ROI,即在 cvCopyImage 前加一行代码:

    cvResetImageROI( ipl );
    cvCopyImage( ipl, m_Ipl );

3、P31增加的成员函数LoadBMP其输入参数类型应为 const char*

在书中,LoadBMP的输入参数类型是 CString,不过我在VS2008下编译时会报错,不能由 CString 类型转换到 const char* 类型。另外OpenCV函数 cvLoadImage 定义为:IplImage* cvLoadImage( const char* filename, int flags ) ,所以在 VS2008 下LoadBMP其输入参数类型应为 const char*。

void MyIplClass::GetIplData( IplImage* ipl )
{
    memcpy( ipl->imageData, m_Ipl->imageData, m_Ipl->imageSize );
}

void MyIplClass::LoadBMP( const char* FileName )
{
    m_Ipl = cvLoadImage( FileName, 1 );
}

上面的 GetIplData 其实是把 m_Ipl->imageData 的内容,复制到了 ipl->imageData里面,注意,这个 ipl 就是传入参数,也就是 
TheImage, 因此,实际上的图片,被保存在了 TheImage 里面(注意,TheImage是一个在程序里面早就初始化好了的图片)。那么,在下面的程序中:

void Cmfc_imgDlg::OnBnClickedReadimg()
{
    // TODO: Add your control notification handler code here
    MyIplClass* img = new MyIplClass;    //实例化MyIplClass类
    const char* filename;
    filename = "C://OpenCV2.0//projects//mfc_img//lena.bmp";
    img->LoadBMP( filename );
    img->GetIplData( TheImage ); 
    delete img;
    RedrawWindow( NULL, NULL, RDW_INVALIDATE );
}

其中的 delete img 只是删除了实例 img,但读入的图像已经保存在 TheImage 中,不影响后续的处理,这样,我们就可以新建一个按钮来执行读入图像后的处理工作,例如:

void Cmfc_imgDlg::OnBnClickedEdgedetect()
{
    // TODO: Add your control notification handler code here
    MyIplClass* img = new MyIplClass;
    img->ProcessIpl( TheImage );
    delete img;
    RedrawWindow( NULL, NULL, RDW_INVALIDATE );
}

最终就得到一个简单的MFC程序如下:

 
OpenCV是一个广受欢迎的开源计算机视觉库 是一个广受欢迎的开源计算机视觉库 ,它提供了 很多函数,实现很多计算机视觉法,从最基本的 滤波到高级物体检测 皆有涵盖 。很多 初学者希望快速掌握 OpenCV OpenCV OpenCVOpenCV的使用方法 ,但 往会 遇到 各种样的困难。 其 实仔细分析,造成这些困难的原因 有两类:第一是 C/C++/C++/C++/C++编程基础不过关; 第二类是不了解算法原理。 解决 这些 困难无非提升编程能力,以及理论基 础知识。 提升编程能力需要多练习,理论知识系统学《数字图 像处理》、《计算机视觉和模式识别等课程,所有这些都不 像处理》、《计算机视觉和模式识别等课程,所有这些都不 像处理》、《计算机视觉和模式识别等课程,所有这些都不 能一蹴而就 , 需要耐下心来认真修炼。 同时我们也 需要 认识到 OpenCV OpenCV OpenCVOpenCV只是一个算法库, 只是一个算法库, 能为我们搭建计算机视觉 应用提供“砖头”。我们并不需要完全精通了算法原理 应用提供“砖头”。我们并不需要完全精通了算法原理 之后 才去使用 OpenCV OpenCV OpenCVOpenCV, 只要了解“砖头”的功能,就可以动手。在实践中学习 才是最高效的学习 方式。 本小册子希望为初学者提供引导,使快速了解 OpenCV OpenCV OpenCVOpenCV的基本数 据结构以及用法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值