Converting 32 bit CBitmap to Grayscale

2019-08-01 16:21发布

问题:

I have done some research and found some existing questions with answers but I am doing something wrong here.

This is my code:

void CMeetingScheduleAssistantApp::SetBitmapAsGrayScale(HBITMAP hbmp)
{
    //converts hbmp to 32-bit grayscale bitmap
    //background colour is retained

    if (!hbmp)
        return;

    HDC hdc = ::GetDC(HWND_DESKTOP);

    BITMAP bm;
    ::GetObject(hbmp, sizeof(bm), &bm);

    BITMAPINFO bi = { 0 };
    bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bi.bmiHeader.biWidth = bm.bmWidth;
    bi.bmiHeader.biHeight = bm.bmHeight;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 32;

    std::vector<COLORREF> pixels(bm.bmWidth * bm.bmHeight);
    GetDIBits(hdc, hbmp, 0, bm.bmHeight, &pixels[0], &bi, DIB_RGB_COLORS);

    //assume that the color at (0,0) is the background color
    COLORREF background = pixels[0];

    for (auto &pixel : pixels)
    {
        if (pixel != background)
        {
            pixel = GetRValue(pixel) * 0.299 + 
                    GetGValue(pixel) * 0.587 + 
                    GetBValue(pixel) * 0.144;
        }
    }

    SetDIBits(hdc, hbmp, 0, bm.bmHeight, &pixels[0], &bi, DIB_RGB_COLORS);

    ::ReleaseDC(HWND_DESKTOP, hdc);
}

When this is applied the menu icon looks like this:

It is all weird! What am I doing wrong?

I saw this so I change one bit to GetBValue(pixel) * 0.114 but it makes no difference.

回答1:

pixel is of type COLORREF, but you are only assigning a single byte to it, i.e. you are populating the blue channel only. For a grayscale image you have to assign the same value to all channels, i.e.

    for (auto &pixel : pixels)
    {
        if (pixel != background)
        {
            auto col = GetRValue(pixel) * 0.299 + 
                       GetGValue(pixel) * 0.587 + 
                       GetBValue(pixel) * 0.114;
            pixel = RGB(col, col, col);
        }
    }

P.S.: 0.114 is the correct value. Using 0.144 can produce values larger than 255, the maximum value per channel.



标签: image mfc