将GDIPlus :: Bitmap转换为cv :: Mat(OpenCV C ++接口)

时间:2011-08-17 21:28:12

标签: image opencv bitmap

我正在尝试将GDIPlus :: Bitmap转换为openCV Mat对象,但我遇到了Access Violations的问题,这意味着我没有做正确的事情,但我已经查看了代码并且,我认为它应该工作。

有没有人看到明显的问题?

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;
}

3 个答案:

答案 0 :(得分:2)

这是一个问题:

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

Mat构造函数的第一个参数是行,第二个是列。所以你应该这样做:

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

这可能会导致访问冲突。

修改

此外,OpenCV图像默认为BGR,而不是RGB。因此,如果您使用此工作,然后使用imshow显示图像,则您的蓝色和红色值将向后。您可以在返回声明之前使用cv::cvtColor(retval, retval, CV_RGB2BGR)调用来解决此问题。

答案 1 :(得分:0)

您可以使用我准备使用的类CGdiPlus,它可以自动从cv :: Mat转换为Gdiplus :: Bitmap,反之亦然:

OpenCV / Tesseract: How to replace libpng, libtiff etc with GDI+ Bitmap (Load into cv::Mat via GDI+)

答案 2 :(得分:0)

由于SSteve注意到Mat构造函数会进行行然后是列,因此请使用height然后使用width。但是,您无需自己进行实际复制。您可以使用其中一个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;
}