[opencv] MFC DC를 이용해 cv::Mat을 출력하기.

원문은 http://stackoverflow.com/questions/28997560/opencv-2-4-displaying-a-cvmat-in-mfc 이곳에서 가져 왔으나, 약간의 문제가 있어 수정한다.

cv::resize() 함수는 기본적으로 같은 비율이 아니더라도 이미지 축소/확대를 지원한다.

만일 MFC에서 같은 비율로 축소/확대를 하기원한다면 (사진뷰어 프로그램과 비슷하게) 아래의 코드를 고려하자.

void DrawCvMat(CDC* pDC, cv::Mat& origin, CRect rect) {  
    CImage mfcImg;
    cv::Mat outImg;
    cv::flip(origin, outImg, 0);
    //흑백이면 채널을3으로
    if (outImg.channels() == 1){
        cv::cvtColor(outImg, outImg, CV_GRAY2BGR);
    }
    //이미지의 크기를 rect에 들어가게 수정합니다.
    if (outImg.cols != rect.Width() || outImg.rows != rect.Height()){
        int newWidth=outImg.cols*(rect.Height() / (double)outImg.rows);
        int newHeight = rect.Height();
        if (newWidth > rect.Width()){
            newWidth = rect.Width();
            newHeight = outImg.rows*(rect.Width() / (double)outImg.cols);
        }
        cv::resize(outImg, outImg, cv::Size(newWidth, newHeight), 0, 0, CV_INTER_NN);
    }
    mfcImg.Create(outImg.cols, outImg.rows,24 );
    BITMAPINFO bitInfo = { {sizeof(BITMAPINFOHEADER),outImg.cols,outImg.rows,1,24},0 };

    void* vp = outImg.data;
    IplImage* iplimage = nullptr;
    if (outImg.cols % 4 != 0 && outImg.isContinuous()){
        iplimage = cvCreateImage(outImg.size(), 8, outImg.channels());
        outImg.copyTo(cv::cvarrToMat(iplimage));
        vp = iplimage->imageData;
    }
    pDC->SetStretchBltMode(HALFTONE);
    StretchDIBits(mfcImg.GetDC(), 0, 0, outImg.cols, outImg.rows, 0, 0, outImg.cols,outImg.rows, vp, &bitInfo, DIB_RGB_COLORS, SRCCOPY);
    if (iplimage != nullptr){
        cvReleaseImage(&iplimage);
    }
    mfcImg.BitBlt(*pDC, (rect.Width() - outImg.cols) / 2 + rect.left, (rect.Height() - outImg.rows) / 2 + rect.top);
    mfcImg.ReleaseDC();
    outImg.release();
}

사용법은 아래와 같다.

void CMFCExample0001View::OnPaint() {  
    CPaintDC dc(this);
    CRect rect;
    this->GetClientRect(&rect);
    DBBufferingMaker dbm(&dc, rect);
    CDC& cdc = dbm.GetDC();
    static cv::Mat img1 = cv::imread("a.jpg",0);
    static cv::Mat img3 = cv::imread("a.jpg", 1);

    CRect rect1 = rect;
    rect1.right = rect1.left + rect1.Width() / 2;
    DrawCvMat(&cdc, img1, rect1);

    CRect rect2 = rect;
    rect2.left = rect2.right - rect2.Width() / 2;
    DrawCvMat(&cdc, img3, rect2);

    dbm.Finalize();
}