Улучшение результата преобразования серой шкалы

Вот цветное меню:

Меню с цветными растровыми изображениями

Вот то же самое меню с некоторыми отключенными пунктами меню и растровыми изображениями, настроенными как оттенки серого:

Меню с растровыми изображениями в оттенках серого

Код, который преобразуется в оттенки серого:

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

Я дальтоник, но кажется, что некоторые из них выглядят не так уж по-разному. Я предполагаю, что это относится к оригинальным цветам в первую очередь?

Было бы хорошо, если бы было более очевидно, что они отключены. Мол, это очень ясно с текстом.

Мы можем?

2 ответа

Решение

Для людей, которые не страдают дальтонизмом, это довольно очевидно.

Просто примените то же уменьшение интенсивности к изображениям, что и к тексту.

Я не проверял ваши ценности. Давайте предположим, что текст белый (интенсивность 100%).

А текст, выделенный серым цветом, имеет интенсивность 50%.

Тогда максимальная интенсивность растрового изображения также должна составлять 50%.

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

Таким образом, вы уменьшаете и далее уменьшаете контраст каждого растрового изображения и избегаете того, чтобы какой-либо пиксель был ярче текста.

Это не имеет прямого отношения к вашему вопросу, но так как вы меняете цвета, вы также можете исправить угловые пиксели, которые выделяются (под угловыми пикселями я не имею в виду пиксели по краям растрового прямоугольника, я имею в виду угол распознаваемого человеком изображения)

Пример, на изображении ниже, есть красный пиксель в углу страницы. Мы хотим найти этот красный пиксель и смешать его с цветом фона, чтобы он не выделялся.

Чтобы определить, являются ли угловые пиксели, проверьте пиксели слева и сверху, если цвет фона слева и сверху, то у вас есть угловой пиксель. Повторите то же самое для верхнего правого, нижнего левого и нижнего правого. Смешайте угловые пиксели с фоном.

Вместо того, чтобы переходить в оттенки серого, вы можете изменить альфа-прозрачность в соответствии с предложением zett42.

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);
Другие вопросы по тегам