将32位CBitmap转换为灰度

时间:2018-04-17 11:13:19

标签: image mfc

我做了一些研究,发现一些现有的questions有答案,但我在这里做错了。

这是我的代码:

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

应用此选项时,菜单图标如下所示:

Image results

这很奇怪!我做错了什么?

我看到this所以我将一位改为GetBValue(pixel) * 0.114,但没有区别。

1 个答案:

答案 0 :(得分:4)

pixel的类型为COLORREF,但您只为其分配一个字节,即您只填充蓝色通道。对于灰度图像,您必须为所有通道分配相同的值,即

    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是正确的值。使用0.144可以产生大于255的值,即每个通道的最大值。