Improving the grey scale conversion result

时间:2018-04-18 17:57:47

标签: image-processing mfc cbitmap

Here is the colour menu:

Menu with colour bitmaps

Here is the same menu with some of the menu items disabled, and the bitmaps set as greyscale:

Menu with greyscale bitmaps

The code that converts to grey scale:

auto col = GetRValue(pixel) * 0.299 + 
           GetGValue(pixel) * 0.587 + 
           GetBValue(pixel) * 0.114;
pixel = RGB(col, col, col);

I am colourblind but it seems that some of them don’t look that much different. I assume it relates to the original colours in the first place?

It would just be nice if it was more obvious they are disabled. Like, it is very clear with the text.

Can we?

2 个答案:

答案 0 :(得分:2)

For people who are not colour blind it's pretty obvious.

Just apply the same intensity reduction to the images that you do to the text.

I did not check your values. Let's assume the text is white (100% intensity).

And the grayed out text is 50% intensity.

Then the maximum intensity of the bitmap should be 50% as well.

for each gray pixel:
  pixel_value = pixel_value / max_pixel_value * gray_text_value

This way you decrease further decrease the contrast of each bitmap and avoid having any pixel brighter than the text.

答案 1 :(得分:1)

这与你的问题没有直接关系,但是因为你正在改变颜色,你也可以修复突出的角落像素(通过角点像素我不是指位图矩形边缘的像素,我的意思是角落人类可识别的图像)

例如,在下图中,页面一角有一个红色像素。我们希望找到红色像素并将其与背景颜色混合,以使其不突出。

enter image description here

要查找角点像素,请检查左侧和顶部的像素,如果左侧和顶部都是背景颜色,则您有一个角点像素。对于右上角,左下角和右下角重复相同的操作。将角点像素与背景混合。

您可以按照zett42的建议更改Alpha透明度,而不是更改为灰度。

void change(HBITMAP hbmp, bool enabled)
{
    if(!hbmp)
        return;
    HDC memdc = CreateCompatibleDC(nullptr);

    BITMAP bm;
    GetObject(hbmp, sizeof(bm), &bm);
    int w = bm.bmWidth;
    int h = bm.bmHeight;
    BITMAPINFO bi = { sizeof(BITMAPINFOHEADER), w, h, 1, 32, BI_RGB };

    std::vector<uint32_t> pixels(w * h);
    GetDIBits(memdc, hbmp, 0, h, &pixels[0], &bi, DIB_RGB_COLORS);

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

    //this is the new background color
    uint32_t bk = GetSysColor(COLOR_MENU);

    //swap RGB with BGR
    uint32_t new_color = RGB(GetBValue(bk), GetGValue(bk), GetRValue(bk));

    //define lambda functions to swap between BGR and RGB
    auto bgr_r = [](uint32_t color) { return GetBValue(color); };
    auto bgr_g = [](uint32_t color) { return GetGValue(color); };
    auto bgr_b = [](uint32_t color) { return GetRValue(color); };

    BYTE new_red = bgr_r(new_color);
    BYTE new_grn = bgr_g(new_color);
    BYTE new_blu = bgr_b(new_color);

    //change background and modify disabled bitmap
    for(auto &p : pixels)
    {
        if(p == old_color)
        {
            p = new_color;
        }
        else if(!enabled)
        {
            //blend color with background, similar to 50% alpha
            BYTE red = (bgr_r(p) + new_red) / 2;
            BYTE grn = (bgr_g(p) + new_grn) / 2;
            BYTE blu = (bgr_b(p) + new_blu) / 2;
            p = RGB(blu, grn, red); //<= BGR/RGB swap
        }
    }

    //fix corner edges
    for(int row = h - 2; row >= 1; row--)
    {
        for(int col = 1; col < w - 1; col++)
        {
            int i = row * w + col;
            if(pixels[i] != new_color)
            {
                //check the color of neighboring pixels:
                //if that pixel has background color,
                //then that pixel is the background 

                bool l = pixels[i - 1] == new_color; //left pixel is background
                bool r = pixels[i + 1] == new_color; //right  ...
                bool t = pixels[i - w] == new_color; //top    ...
                bool b = pixels[i + w] == new_color; //bottom ...

                //we are on a corner pixel if:
                //both left-pixel and top-pixel are background or
                //both left-pixel and bottom-pixel are background or
                //both right-pixel and bottom-pixel are background or
                //both right-pixel and bottom-pixel are background
                if(l && t || l && b || r && t || r && b)
                {
                    //blend corner pixel with background
                    BYTE red = (bgr_r(pixels[i]) + new_red) / 2;
                    BYTE grn = (bgr_g(pixels[i]) + new_grn) / 2;
                    BYTE blu = (bgr_b(pixels[i]) + new_blu) / 2;
                    pixels[i] = RGB(blu, grn, red);//<= BGR/RGB swap
                }
            }
        }
    }

    SetDIBits(memdc, hbmp, 0, h, &pixels[0], &bi, DIB_RGB_COLORS);
    DeleteDC(memdc);
}

用法:

CBitmap bmp1, bmp2;

bmp1.LoadBitmap(IDB_BITMAP1);
bmp2.LoadBitmap(IDB_BITMAP2);

change(bmp1, enabled);
change(bmp2, disabled);