Tricks & Notes of Using OpenCV with MFC

Introduction


I’m currently working on a project that requires sufficient knowledge of the integration of OpenCV and MFC development. Therefore, I believe that it is of great importance to record everything needed to improve myself and help with further implementation.

How to Display A CV::Mat


The tutorials or solutions I could find online about image processing, involving with two of these technologies are all too ancient which utilize a class called CvvImage, the one included in earlier versions of OpenCV, in order to show images of the format of IplImage. The code segment below, however, shows a different approach of displaying images of the newer Mat, which is essentially better than any of the previous image formats.

void DrawPicToHDC(cv::Mat cvImg, UINT ID, bool bOnPaint)
{
    // Get the HDC handle information from the ID passed
    CDC *pDC = GetDlgItem(ID)->GetDC();
    HDC hDCDst = pDC->GetSafeHdc();
    CRect rect;
    GetDlgItem(ID)->GetClientRect(&rect);
    cv::Size winSize(rect.right, rect.bottom);

    // Resize the source to the size of the destination image if necessary
    cv::Mat cvImgTmp(winSize, CV_8UC3);
    if (cvImg.size() != winSize)
    {
        cv::resize(cvImg, cvImgTmp, winSize);
    }
    else
    {
        cvImgTmp = cvImg;
    }

    // Rotate the image
    cv::flip(cvImgTmp,cvImgTmp,0);

    // Initialize the BITMAPINFO structure
    BITMAPINFO bitInfo;
    bitInfo.bmiHeader.biBitCount = 24;
    bitInfo.bmiHeader.biWidth = winSize.width;
    bitInfo.bmiHeader.biHeight = winSize.height;
    bitInfo.bmiHeader.biPlanes = 1;
    bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitInfo.bmiHeader.biCompression = BI_RGB;
    bitInfo.bmiHeader.biClrImportant = 0;
    bitInfo.bmiHeader.biClrUsed = 0;
    bitInfo.bmiHeader.biSizeImage = 0;
    bitInfo.bmiHeader.biXPelsPerMeter = 0;
    bitInfo.bmiHeader.biYPelsPerMeter = 0;

    // Add header and OPENCV image's data to the HDC
    StretchDIBits(hDCDst, 0, 0,
        winSize.width, winSize.height, 0, 0,
        winSize.width, winSize.height,
        cvImgTmp.data, &bitInfo, DIB_RGB_COLORS, SRCCOPY);

    ReleaseDC( pDC );
}

Key Functions


The following functions are quoted from a program called CVMFC that illustrates the use of OpenCV within an MFC application. As a beginner of development of image processing, I really appreciate the work that’s been accomplished in the demo program and the valuable inspiration the source code constantly gives me.

  • StrechDIBits

    This is one of the functions in Windows API. It copies an image source to a destination rectangle and modifies the size of the image accordingly.

    int StretchDIBits(
         HDC hdc,  //A handle to the destination device context             
         int XDest, YDest, nDestWidth, nDestHeight,  //Parameters of the destination rectangle
         int XSrc, YSrc, nSrcWidth, nSrcHeight,  //Parameters of the source rectangle
         CONST VOID *lpBits,  //A pointer to the image bits, which are stored as an array of bytes      
         CONST BITMAPINFO *lpBitsInfo, 
         // A pointer to a BITMAPINFO structure that contains information about the DIB
         UINT iUsage,  //bmiColors
         DWORD dwRop  //A raster-operation code 
    );
  • CtreateMapInfo

    This is a function that creates BITMAPINFO for the given image, a structure that defines the dimensions and color information for a DIB(Device-Independent Bitmap).

    LPBITMAPINFO CtreateMapInfo(IplImage* workImg, int flag){
         BITMAPINFOHEADER BIH={40,1,1,1,8,0,0,0,0,0,0};
         LPBITMAPINFO lpBmi;
         int wid,hei,bits,colors,i;
    
         wid =workImg->width;
         hei =workImg->height;
         bits=workImg->depth*workImg->nChannels;
    
         if (bits>8) 
            colors=0;
         else 
            colors=1<<bits;
    
         lpBmi=(LPBITMAPINFO) malloc(40+4*colors);
         BIH.biWidth = wid;
         BIH.biHeight = hei;
         BIH.biBitCount = (BYTE) bits;
         memcpy(lpBmi,&BIH,40);                  
    
         //If workImg represents an 8-bit or 256-color image
         if (bits==8) {                          
            if (flag==1) {  //Grayscale         
                for (i=0;i<256;i++) {
                    VgaColorTab[i].rgbRed=VgaColorTab[i].rgbGreen = 
                            VgaColorTab[i].rgbBlue=(BYTE) i;
                }
                memcpy(lpBmi->bmiColors,VgaColorTab,1024);
            }
            else if (flag==2) {  //Default
                memcpy(lpBmi->bmiColors,VgaDefPal,1024);
            }
            else if (flag==3) {  //Custom           
                memcpy(lpBmi->bmiColors,VgaColorTab,1024);
            }
         }
         return(lpBmi);
    }
  • imageClone

    int imageClone(IplImage* pi, IplImage** ppo){
         if (*ppo) {
             cvReleaseImage(ppo);                
         }
         (*ppo) = cvCloneImage(pi);            
    
         return(1);
    }
  • imageReplace

    int imageReplace(IplImage* pi, IplImage** ppo){
         if (*ppo) 
             cvReleaseImage(ppo);               
         (*ppo) = pi;                            
         return(1);
    }
  • imageType

    This function identifies the image type.

    int  imageType(IplImage* p) 
    {
        int  i,j,k,bpl,n,pg[256];
        BYTE *buf;
        k=p->nChannels;
        if (k==1) {                             
            for (i=0;i<256;i++) {
                pg[i]=0;
            }
            buf=(BYTE*)p->imageData;
            bpl=p->widthStep;
            for (i=0;i<p->height;i++) {
                for (j=0;j<p->width;j++){
                    pg[buf[j]]++;
                } 
                buf+=bpl;
            }
            for (i=0,n=0;i<256;i++) {
                if (pg[i]) n++;
            }
            if (n==2) k=-1;           
        }
    
        return(k);
    }
  • CCVMFCDoc::Load

    BOOL CCVMFCDoc::Load(IplImage** pp, LPCTSTR csFileName){
        IplImage* pImg=NULL;
    
        pImg = cvLoadImage(csFileName,-1);      
        if (!pImg) 
            return(false);
    
        cvFlip(pImg);                    
        if (*pp) {
            cvReleaseImage(pp);
        }
        (*pp)=pImg;
        m_Display=0;
        return(true);
    }
  • CCVMFCView::OnDraw

    void CCVMFCView::OnDraw(CDC* pDC)
    {
        CCVMFCDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
        if (pDoc->pImg!=NULL)   {
            if (pDoc->m_Display==0) {
                imageClone(pDoc->pImg,&saveImg);
                m_dibFlag=imageClone(saveImg,&workImg);
                m_ImageType=imageType(workImg);
                m_SaveFlag=m_ImageType;
                pDoc->m_Display=1;
            }
        }
        if (m_dibFlag) {                
            if (m_lpBmi)
                free(m_lpBmi);
            m_lpBmi=CtreateMapInfo(workImg,m_dibFlag);
            m_dibFlag=0;
            CSize  sizeTotal;
            sizeTotal = CSize(workImg->width,workImg->height);
            SetScrollSizes(MM_TEXT,sizeTotal);  
        }
        char *pBits;
    
        if(m_CaptFlag==1)
            pBits=m_Frame->imageData;
        else if(workImg)  
            pBits=workImg->imageData;
    
        if (workImg) {                          
            StretchDIBits(pDC->m_hDC,
                    0,0,workImg->width,workImg->height,
                    0,0,workImg->width,workImg->height,
                    pBits,m_lpBmi,DIB_RGB_COLORS,SRCCOPY);
        }
    }

Because the program was implemented several years ago, the functions it contains use old OpenCV APIs, which should be updated for the development of C++ applications. For instance, the memory deallocation CV::Mat.release() will ONLY be needed under certain circumstances because it is handled automatically in most cases.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值