2
votes

I'm trying to develop a small C++/CLI wrapper around OpenCV for use in a C# application. I can't use Emgu since it's for a commercial application.

I'm facing a problem when I'm trying to convert from System.Drawing.Bitmap to OpenCV Mat.

I have the following code:

cv::Mat BitmapToMat(System::Drawing::Bitmap^ bitmap)
{
    System::Drawing::Rectangle blank = System::Drawing::Rectangle(0, 0, bitmap->Width, bitmap->Height);
    System::Drawing::Imaging::BitmapData^ bmpdata = bitmap->LockBits(blank, System::Drawing::Imaging::ImageLockMode::ReadWrite, System::Drawing::Imaging::PixelFormat::Format24bppRgb);
    cv::Mat cv_img(cv::Size(bitmap->Width, bitmap->Height), CV_8UC3, bmpdata->Scan0.ToPointer(), cv::Mat::AUTO_STEP);
    bitmap->UnlockBits(bmpdata);

    return cv_img;
}

I'm using it in cpp file to test out the generated Mat like this:

Mat image = BitmapToMat(templateImage);
cv::imwrite("some2.jpg", image);

But the image produced is completely distorted (see images)

INPUT BITMAP IMAGE

ORIGINAL IMAGE

RESULT MAT IMAGE SAVED TO FILE

RESULT IMAGE

1
Can you get your bitmap "step" to replace cv::Mat::AUTO_STEP ? - Ziri
@Ziri I removed that and checked, still no difference - mrid
What about OpenCVSharp? That one's BSD licensed as opposed to the apparently GPLd Emgu. - Dan Mašek
What's the stride of the BitmapData? If I'm not mistaken, windows bitmaps ten to have the rows aligned on multiples of 4. Hence step should be set to the stride, otherwise (when image width is not a multiple of 4 as is the case here) you don't skip the padding and the following rows get each shifted right by a few pixels -- quite evident from your second image. - Dan Mašek

1 Answers

1
votes

Windows bitmaps are padded. You want to calculate "width in bytes" of the bitmap row, and supply that instead of cv::Mat::AUTO_STEP:

int wb = ((bitmap->Width * 24 + 31) / 32) * 4;
cv::Mat cv_img(cv::Size(bitmap->Width, bitmap->Height), 
    CV_8UC3, bmpdata->Scan0.ToPointer(), wb);