zoukankan      html  css  js  c++  java
  • 【OpenCV学习笔记3】OpenCV GUI 之 搭建MFC+OpenCV開發環境

    单文档程序    VC6.0+OpenCV1.0

    SkySeraph Jun.25th 2010  HQU  

    zgzhaobo@gmail.com  452728574

     更多精彩请直接访问SkySeraph个人站点www.skyseraph.com 

    步骤:

    1  创建SDI MFC工程,单文档,最好选择use MFC As a static library  (以防止MFC中使用opencv的内存泄露问题)

    2  加入OpenCV库支持[头文件和库文件]:菜单Project->Settings->Link->Input->Object/library modules中加入cxcore.lib cv.lib ml.lib cvaux.lib highgui.lib cvcam.lib

    3  在Doc类开头添加HighGui.h 的头文件包含, 同时添加一个变量CImage m_image; [在定义处,建议public,VC下]

    4  添加2个虚函数,用来打开和保存文件:OnOpenDocument 和 OnSaveDocument  如下:

    BOOL CSDI OpenCVDoc::OnOpenDocument(LPCTSTR lpszPathName){
        if (!CDocument::OnOpenDocument(lpszPathName)) return FALSE;
        // TODO: Add your specialized creation code here
        m_image.Load(lpszPathName);
        return TRUE;
    }

    BOOL CSDI OpenCVDoc::OnSaveDocument(LPCTSTR lpszPathName){
        // TODO: Add your specialized code here and/or call the base class
        m_image.Save(lpszPathName);
        return TRUE;

       // return CDocument::OnSaveDocument(lpszPathName); //原因:会导致保存后的图片大小变为0 
    }

    5   在View类添加显示函数

    void CSDI_OpenCVView::OnDraw(CDC* pDC)
    {
            CSDI_OpenCVDoc* pDoc = GetDocument();
            ASSERT_VALID(pDoc);
            // TODO: add draw code for native data here
            CImage & img = pDoc ->m_image; //CImage类 其实就是CvvImage类,可以直接替换使用

            CRect r;
            GetClientRect (&r);
            img.DrawToHDC(pDC->GetSafeHdc() ,r);
    }

    6  添加菜单,实现CANNY

    ①修改前面的 m_image.Load(lpszPathName);为 m_image.Load(lpszPathName,0); //强制转换读取图像为8位深度灰度图

    ②添加菜单ImageProcessing,子菜单CANNY,在Doc类中添加ID号为IDM_CANNY的COMMAND消息响应函数,代码如下

    void CSDI_OpenCVDoc::OnCanny() //菜单处理函数

    {

    // TODO: Add your command handler code here

    IplImage* img;

    img=m_image.GetImage();//由CImage类 返回一个IplImage* 指针,因为:IplImage* GetImage() { return m_img; };

    cvCanny(img,img,50,150,3);

    UpdateAllViews(NULL);

    }

    说明

    1. 原创】MFC中快速应用OpenCV教程
    2. 关于图片太大,无法放入view里的一个解决方案,请看 feixiaolin 的帖子 opencv 数据读写操作+图像噪声+ MFC下OpenCV源代码 以及 如何插入滚动条
    3. OpenCV绘图函数DrawToHDC的一个简要解释
    4. 在opencv1.0版本中,使用上面介绍的canny的方法,存在单通道图片无法打开的错误,具体的原因请看这里,这主要是由于opencv1.0中的一个bug所导致的。原因
    5. 在opencv 1.1版本中使用,可能导致MFC的程序无法退出,解决办法请看这里 程序无法正常退出    解决:1.1下不能退出的问题 需要将1.1中_highgui.h中的 #define HAVE_VIDEOINPUT 1这句 注释掉,重新编译OpenCv的Highgui工程,重新生成Highgui.lib就可以了 
    6. 注意,其中的 CImage 其实就是 CvvImage 这两个可以直接替换使用。
    7. OLE错误对话框的问题,请看这里 如何解决OLE的问题的论坛讨论

    参考资料

    http://www.opencv.org.cn/index.php/MFC%E4%B8%AD%E5%BF%AB%E9%80%9F%E5%BA%94%E7%94%A8OpenCV   MFC中快速应用OpenCV

    http://www.opencv.org.cn/forum/viewtopic.php?f=1&t=4932&p=18215#p18136   相关问题

    对话框程序   VC6.0+OpenCV1.0

     

    SkySeraph Oct.28th 2010  HQU  

    zgzhaobo@gmail.com  452728574

    Latest Modified Date:Oct.29th 2010 HQU

    步骤:

    1  创建工程:MFC_OpenCV_Dlg     对话框

    2  加入OpenCV库支持[头文件和库文件]

    菜单Project->Settings->Link->Input->->Object/library modules 加入 cxcore.lib cv.lib ml.lib cvaux.lib highgui.lib cvcam.lib

    3  添加头文件和全局宏

    在CMFC_OpenCV_Dlg.h开头 #include "resource.h"  下 加入如下代码

    #include "cv.h"

    #include "HighGUI.h"

    #define IMAGE_WIDTH 512  //此处假设读入和显示的图像都是512*512(像素)大小的彩色图像,读者可自行修改

    #define IMAGE_HEIGHT 512

    #define IMAGE_CHANNELS 3

    4  添加IplImage*变量并初始化及内存释放

    在CMFC_OpenCV_DlgDlg  右击添加一个 IplImage* 类型的变量 TheImage,

    再双击该类下的OnInitDialog,在“// TODO: Add extra initialization here”下面添加TheImage 的初始化代码:

        CvSize ImgSize;
        ImgSize.height = IMAGE_HEIGHT;
        ImgSize.width = IMAGE_WIDTH;
        TheImage = cvCreateImage( ImgSize, IPL_DEPTH_8U, IMAGE_CHANNELS );

    接着在CMFC_OpenCV_DlgApp 下面的成员列表中双击 InitInstance,

    在两个“// TODO: Place code here to handle when the dialog is…”下面添加:

    cvReleaseImage( &dlg.TheImage );//释放内存

    即按下“OK”或“Cancel”时,释放TheImage占用的内存。//按下OK或Cancel 会调用InitInstance,看源代码

    5  窗口重绘

    在CMFC_OpenCV_DlgDlg ,双击 OnPaint,在 if(IsIconic())…的 else 里添加以下代码,用来重绘窗口:

            CDialog::OnPaint();                    // 重绘对话框
            CDialog::UpdateWindow();          // 更新windows窗口,如果无这步调用,图片显示还会出现问题
            ShowImage( TheImage, IDC_ImgShowCtrl );    // 重绘图片函数

    6  添加控件及成员函数

    1个Edit

     

    关联变量m_Path

     

    1个picture

    ID:IDC_ImgShowCtrl

     

     

    4个Button

    ID:IDC_ChooseFile   用来选择图片并保存路径到m_Path

    ID:IDC_ShowImage     用来显示m_Path路径上的图片

    ID:IDC_EdgeDetect  边缘检测测试

    ID:IDC_Test               扩展/自定义

    消息响应函数:OnChooseFile()

    消息响应函数:OnShowImage()

    消息响应函数:OnEdgeDetect()

    消息响应函数:OnTest()

     詳細代碼見下

    在CMFC_OpenCV_DlgDlg,添加两个成员函数void ShowImage( IplImage* img, UINT ID ) 和 void ResizeImage(IplImage* img),代码如下:

    void CMFC_OpenCV_DlgDlg::ShowImage(IplImage *img, UINT ID) //ID 是Picture Control控件的ID号

    {

    // 获得显示控件的 DC

    CDC* pDC = GetDlgItem( ID ) ->GetDC();

    // 获取 HDC(设备句柄) 来进行绘图操作                

    HDC hDC = pDC ->GetSafeHdc();                                

    CRect rect;

    GetDlgItem(ID) ->GetClientRect( &rect );

    /*

    CBrush brush(RGB(255,255,255));

    pDC->FillRect(&rect,&brush);

    */

    // 求出图片控件的宽和高

    int rw = rect.right - rect.left;                        

    int rh = rect.bottom - rect.top;

    // 读取图片的宽和高

    int iw = img->width;        

    int ih = img->height;

    // 使图片的显示位置正好在控件的正中

    int tx = (int)(rw - iw)/2;        

    int ty = (int)(rh - ih)/2;

    SetRect( rect, tx, ty, tx+iw, ty+ih );//

    // 复制图片

    CvvImage cimg;

    cimg.CopyOf( img );

    // 将图片绘制到显示控件的指定区域内        

    cimg.DrawToHDC( hDC, &rect );        

    ReleaseDC( pDC );

    }

    void CMFC_OpenCV_DlgDlg::ResizeImage(IplImage *img)

    {

    // 图片的大小

    int width=(int)IMAGE_WIDTH;                        // 宽

    int height=(int)IMAGE_HEIGHT;                // 高

    float max_w_h=(float) (IMAGE_WIDTH>IMAGE_HEIGHT)? IMAGE_WIDTH : IMAGE_HEIGHT;

    // 读取图片的宽和高

        int w = img->width;

        int h = img->height;// 找出宽和高中的较大值者

        int max = (w > h)? w: h;

    // 计算将图片缩放到TheImage区域所需的比例因子

        //float scale = (float) ( (float) max / 512.0f );

    float scale = (float) ( (float) max / max_w_h );

       

        // 缩放后图片的宽和高

        int nw = (int)( w/scale );

        int nh = (int)( h/scale );

    // 为了将缩放后的图片存入 TheImage 的正中部位,需计算图片在 TheImage 左上角的期望坐标值

        int tlx = (nw > nh)? 0: (int)(width-nw)/2;

        int tly = (nw > nh)? (int)(height-nh)/2: 0;

    /*        //确保为3通道图像

    IplImage *temp = 0; //定义中转图像指针

    temp = cvCreateImage( cvGetSize(img), img->depth, 3);

    if(1==img->nChannels)        // 如果是单通道的 图像,转换成3通道的

    {

    cvConvertImage(img,temp,CV_CVTIMG_SWAP_RB);        // P70

    //CV_CVTIMG_FLIP   (flip vertically)    CV_CVTIMG_SWAP_RB (swap the R and B channels)

    }

    else if(3==img->nChannels)

    {

    temp=cvCloneImage(img);        

    }

    else AfxMessageBox(_T("channel wrong on function show picture !"));

    */

    // 设置 TheImage 的 ROI 区域,用来存入图片 img

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

    // 对图片 img 进行缩放,并存入到 TheImage 中

        cvResize( img, TheImage,CV_INTER_AREA ); //P255

    // 重置 TheImage 的 ROI 准备读入下一幅图片

        cvResetImageROI( TheImage );

    //cvReleaseImage(&temp);        // 释放 中转 图像指针

    }

    void CMFC_OpenCV_DlgDlg::OnChooseFile()

    {

    // TODO: Add your control notification handler code here

    CFileDialog dlg(

            TRUE, NULL, NULL,

            OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,

            _T("All Files (*.*) |*.*||"), AfxGetMainWnd()

            );                                        // 选项图片的约定

        dlg.m_ofn.lpstrTitle = _T("Open Image");    // 打开文件对话框的标题名

        if( dlg.DoModal() != IDOK )                    // 判断是否获得图片

            return;

       

        m_Path.SetWindowText( dlg.GetPathName() );            // 获取图片路径

    }

    void CMFC_OpenCV_DlgDlg::OnShowImage()

    {

    // TODO: Add your control notification handler code here

    CString mPath;

    m_Path.GetWindowText(mPath);

    if(mPath=="")

    {

    AfxMessageBox(_T("file path is empty ,please choose file!"));

    return;

    }

    IplImage* ipl = cvLoadImage( mPath, CV_LOAD_IMAGE_COLOR );    // 读取图片、缓存到一个局部变量 ipl 中

        if( !ipl )                                    // 判断是否成功载入图片

            return;

        if( TheImage )                                // 对上一幅显示的图片数据清零

            cvZero( TheImage );

       

    ResizeImage( ipl );    // 对读入的图片进行缩放,使其宽或高最大值者刚好等于 512,再复制到 TheImage 中

        ShowImage( TheImage, IDC_ImgShowCtrl );            // 调用显示图片函数   

        cvReleaseImage( &ipl );                        // 释放 ipl 占用的内存

    }

    void CMFC_OpenCV_DlgDlg::OnEdgeDetect()

    {

    // TODO: Add your control notification handler code here

    CString mPath;

    m_Path.GetWindowText(mPath);

    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( TheImage, gray, CV_BGR2GRAY );

        cvCanny( gray, edge, 30, 100, 3 );

        cvCvtColor( edge, TheImage, CV_GRAY2BGR );  

    if(!TheImage)

    {

    AfxMessageBox(_T("PictureCtrl is empty ,please choose Pictrue!"));

    return;

    }

        ShowImage( TheImage, IDC_ImgShowCtrl );            // 调用显示图片函数

        cvReleaseImage( &gray );

        cvReleaseImage( &edge );

    }

    效果:

    圖片弄不上,真暈。。。誰告訴俺如何插入圖片? %>_<%   ^_^

    参考资料

    书:OpenCV教程-基础篇

    http://blog.csdn.net/chenyusiyuan/archive/2009/10/29/4744097.aspx   晨宇思远OpenCV学习笔记9

    http://www.site.uottawa.ca/~laganier/tutorial/opencv+directshow/cvision.htm  A step-by-step guide to the use of Microsoft Visual C++ and the Intel OpenCV library

    Author:         SKySeraph

    Email/GTalk: zgzhaobo@gmail.com    QQ:452728574

    From:         http://www.cnblogs.com/skyseraph/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,请尊重作者的劳动成果。

  • 相关阅读:
    C++的几个晦涩特性
    高效学习的工具Mnemosyne
    允许OSQA上传任意类型的文件
    新一代J2ME终端标准MSAfor CLDC——解读JSR248
    JAVA实现简单的HTTP服务器
    什么是Web 2.0
    Java 手机与空间制图服务(WMS)应用集成
    广西移动SP结算工作管理流程
    2007年Enterprise 2.0的10大趋势
    移动虚拟专用网的发展与未来应用
  • 原文地址:https://www.cnblogs.com/skyseraph/p/1863992.html
Copyright © 2011-2022 走看看