-1

I am trying to load an Gdiplus bitmap of 8 bit depth to an opencv mat. the image is in greyscale.

Greyscale Image of 8bit:

Greysacle Image of 8bit.

this is the VC++ code snippet I am using to convert it into cv::mat. But using this when I convert I am getting a faded image of the original image in the cv::mat. What could be the reason?

// Creating the m_Bitmap 
Gdiplus::Bitmap bit(152, 152, PixelFormat8bppIndexed);
m_Bitmap = bit.Clone(0, 0, bit.GetWidth(), bit.GetHeight(), PixelFormat8bppIndexed);

// Later Different paths are added to this bitmap

// Converting this bitmap to cv::mat
Gdiplus::PixelFormat format = m_Bitmap->GetPixelFormat();
if (format == PixelFormat8bppIndexed)
{
            Gdiplus::BitmapData bitmapData;
            Gdiplus::Rect rect(0, 0, width, height);
            m_Bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, format, &bitmapData);
            
            cv::Mat nmat = cv::Mat(height, width, CV_8UC1, static_cast<unsigned char*>(bitmapData.Scan0), bitmapData.Stride).clone();
}

Original bitmap Image (m_Bitmap):

enter image description here

This is the image preview of cv::mat nmat:

enter image description here

I need to have the same image as the source to be loaded into the cv::mat but that is not happening here.

Note: When the bitmap was in PixelFormat32bppARGB

The below approach has made the correct conversion and the data in the cv::mat was proper. (like there was no fading thing)

    // Lock the gdiplus::bitmap object to get direct access to the pixel data
    Gdiplus::BitmapData bitmapData;
    Gdiplus::Rect rect(0, 0, width, height);
    m_Bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, format, &bitmapData);

    // Create a cv::Mat object with the same dimensions and type as the gdiplus::bitmap object
    cv::Mat nmat = cv::Mat(height, width, CV_8UC4, static_cast<unsigned char*>(bitmapData.Scan0), bitmapData.Stride).clone();

    // Convert to single channel image for performing open::CV operations
    cv::Mat singleChannelImage;
    cv::cvtColor(nmat, singleChannelImage, cv::COLOR_RGBA2GRAY);


    m_Bitmap->UnlockBits(&bitmapData);

enter image description here

14
  • Are you sure nmat actually has "faded" pixels (and it's not misrepresentation in the debug preview display) ? you can use cv::imwrite to save to file and check. Commented May 16, 2024 at 12:36
  • You cannot directly copy data from gdi+ bitmap which has indexed format into cv::Mat because you then copy indices instead colors to which indices refer. Your gdi+ bitmap has indices + colors palette (from palette by indices you read colors). [1] Convert gdi+ bitmap into PixelFormat24bppRGB by LockBits. [2] Create from this data cv::Mat. [3] Use cv::cvtColor to convert 3 channels image into one - grayscale. Commented May 16, 2024 at 12:55
  • @rafix07 isn't the index just a 1 to 1 trivial mapping in case of 8 bit grayscale ? (i.e. the index is the same as the grayscale ?) Commented May 16, 2024 at 13:41
  • @wohlstad I could not find any information you write about in offical Gdi+ reference (it could be the best to work in such way i.e index is value of grayscale), that is why I put my comment :) Commented May 16, 2024 at 14:25
  • 1
    @rafix07 i tried out you approach and it worked! Thanks for clarification. I have added my solution to the main post. Commented May 30, 2024 at 10:43

1 Answer 1

0

This worked for me

  1. Convert gdi+ bitmap into PixelFormat24bppRGB by LockBits.
  2. Create from this data cv::Mat.
  3. Use cv::cvtColor to convert channels image into one - grayscale

as suggested by @rafix07

Gdiplus::PixelFormat format = m_Bitmap->GetPixelFormat();
if (format == PixelFormat8bppIndexed)
{  
// Step 1: Convert GDI+ bitmap into PixelFormat24bppRGB
        
Gdiplus::Bitmap tempBitmap24(width, height, PixelFormat24bppRGB);
Gdiplus::Graphics g(&tempBitmap24);
Gdiplus::Rect rect(0, 0, width, height);
        
g.DrawImage(m_Bitmap, rect);
            
    
// Step 2: Create cv::Mat from the converted data               
cv::Mat nmat(height, width, CV_8UC3);
        
for (int y = 0; y < height; y++)                
{               
for (int x = 0; x < width; x++)                 
{                       
Gdiplus::Color pixelColor;                      
tempBitmap24.GetPixel(x, y, &pixelColor);                   
cv::Vec3b& pixel = nmat.at<cv::Vec3b>(y, x);                    
pixel[0] = pixelColor.GetBlue();                        
pixel[1] = pixelColor.GetGreen();                   
pixel[2] = pixelColor.GetRed();         
}           
}
        
cv::Mat singleChannelImage;
// Step 3: Convert 3-channel image into grayscale
cv::cvtColor(nmat, singleChannelImage, cv::COLOR_RGBA2GRAY);

}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.