2011-08-17 750 views
0

我試圖將GDIPlus :: Bitmap轉換爲openCV Mat對象,但是我遇到了訪問衝突問題,這意味着我'我沒有做正確的事情,但我一遍又一遍地查看了代碼,我認爲它應該可以工作。將GDIPlus :: Bitmap轉換爲cv :: Mat(OpenCV C++接口)

有沒有人看到一個明顯的問題?

cv::Mat ConvertToOpenCV(Gdiplus::Bitmap &image) { 
    cv::Mat *retval = new cv::Mat(
     image.GetWidth(), image.GetHeight(), CV_8UC3 
    ); 

    Gdiplus::BitmapData source; 

    Gdiplus::Rect rect(0, 0, image.GetWidth(), image.GetHeight()); 
    Gdiplus::Status status = 
     image.LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat24bppRGB, &source); 
    if (status != Gdiplus::Ok) { 
     // Some error condition 
     return retval; // No image copied 
    } 

    BYTE *destination = (BYTE *)retval->data; 

    for (int y = 0; y != source.Height; ++y) { 
     BYTE *src = (BYTE *) source.Scan0 + y * source.Stride; 
     BYTE *dst = (BYTE *)(destination + y * retval->step); 
     memcpy(dst, src, 3 * source.Width); // Access Violation happens here 
    } 

    image.UnlockBits(&source); 

    return retval; 
} 

回答

2

這裏有一個問題:

cv::Mat *retval = new cv::Mat(
    image.GetWidth(), image.GetHeight(), CV_8UC3 
); 

墊子構造函數的第一個參數是行,第二個是列。所以你應該這樣做:

cv::Mat *retval = new cv::Mat(
    image.GetHeight(), image.GetWidth(), CV_8UC3 
); 

這可能會導致訪問衝突。

編輯

此外,OpenCV的圖像默認BGR,而不是RGB。所以,如果你得到這個工作,然後用imshow顯示圖像,你的藍色和紅色值將會落後。您可以在退貨聲明之前通過致電cv::cvtColor(retval, retval, CV_RGB2BGR)解決此問題。

+0

Doh!非常感謝您的關注,我甚至都沒有想過看看!這是一個很好的測試用例,我需要添加到我的單元測試中。我相信我所有的測試圖像都是正方形的,這會隱藏這種行爲! 顏色順序對我來說並不重要,因爲我正在轉換爲灰度並對圖像進行區分,所以我沒有打擾它。 非常感謝您抓住我愚蠢的錯誤! – RussTheAerialist

+0

我一定找到了它,因爲我很習慣在自己的代碼中找到類似的東西!當我使用MAX()時,我無法告訴你我使用了MIN()多少次。 :-) – SSteve

0

由於SSteve注意到墊構造走行然後列,所以使用高度和寬度。但是不需要自己做實際的拷貝。您可以使用其中一個Mat構造函數來覆蓋現有數據而不進行復制,然後通過調用克隆成員函數強制它複製。

唯一的另一個麻煩是Gdiplus :: Bitmap理論上支持像素佈局的加載;然而,其中大部分都非常奇特。您可以按如下方式處理簡單情況:

cv::Mat GdiPlusBitmapToOpenCvMat(Gdiplus::Bitmap* bmp) 
{ 
    auto format = bmp->GetPixelFormat(); 
    if (format != PixelFormat24bppRGB) 
     return cv::Mat(); 

    int wd = bmp->GetWidth(); 
    int hgt = bmp->GetHeight(); 
    Gdiplus::Rect rcLock(0, 0, wd, hgt); 
    Gdiplus::BitmapData bmpData; 

    if (!bmp->LockBits(&rcLock, Gdiplus::ImageLockModeRead, format, &bmpData) == Gdiplus::Ok) 
     return cv::Mat(); 

    cv::Mat mat = cv::Mat(hgt, wd, CV_8UC3, static_cast<unsigned char*>(bmpData.Scan0), bmpData.Stride).clone(); 

    bmp->UnlockBits(&bmpData); 
    return mat; 
}