2011-08-17 749 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; 
}