C # Color Blend и вычисление непрозрачности / альфа как в Photoshop

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

Photoshop делает это, создавая фильтр, задавая цвет, выбирая «Смешать» и затем применяя альфа-канал. Альфа применяется к фильтру, а не к базовому изображению.

Я беру два цвета, базовое изображение и цвет наложения, которые нужно смешать, и конвертирую их в HSL. Я рисую Blend, беря Hue / Saturation из оверлея и Luminosity из базы и создавая новый цвет HSL. Затем я конвертирую его в RGB и записываю этот пиксель в растровое изображение поверх исходного базового цвета.

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

Я не вижу необходимости в коде для этого вопроса, но если он вам нужен, я могу опубликовать его.

Спасибо


person Terrordoll    schedule 28.10.2015    source источник
comment
Ой, моя плохая! Я только что нашел уравнение, и все работает как шарм! stackoverflow.com/questions/746899/ В следующий раз я буду искать более тщательно!   -  person Terrordoll    schedule 29.10.2015


Ответы (1)


Я решил эту проблему так (background.png и colorWithAlpha.png имеют одинаковые размеры):

Bitmap bg = new Bitmap("background.png");
Bitmap overlay = new Bitmap("colorWithAlpha.png");
float m = 0;
Color c;
for (int i = 0; i < bg.Width; i++)
{
    for (int j = 0; j < bg.Height; j++)
    {
        m = overlay.GetPixel(i, j).A / 255f;
        c = HSVtoRGB(overlay.GetPixel(i,j).GetHue(), overlay.GetPixel(i,j).GetSaturation(), bg.GetPixel(i, j).GetBrightness());
        c = Color.FromArgb((int)(m * c.R + (1 - m) * bg.GetPixel(i, j).R), (int)(m * c.G + (1 - m) * bg.GetPixel(i, j).G), (int)(m * c.B + (1 - m) * bg.GetPixel(i, j).B));
        bg.SetPixel(i, j, c);
    }
}

public static Color HSVtoRGB(float hue, float saturation, float value)
{
    // HSV contains values scaled as in the color wheel:
    // that is, all from 0 to 255.

    // for ( this code to work, HSV.Hue needs
    // to be scaled from 0 to 360 (it//s the angle of the selected
    // point within the circle). HSV.Saturation and HSV.value must be
    // scaled to be between 0 and 1.

    double h;
    double s;
    double v;

    double r = 0;
    double g = 0;
    double b = 0;

    // Scale Hue to be between 0 and 360. Saturation
    // and value scale to be between 0 and 1.
    h = ((double)hue / 255 * 360) % 360;
    s = (double)saturation / 255;
    v = (double)value / 255;

    if (s == 0)
    {
        // If s is 0, all colors are the same.
        // This is some flavor of gray.
        r = v;
        g = v;
        b = v;
    }
    else
    {
        double p;
        double q;
        double t;

        double fractionalSector;
        int sectorNumber;
        double sectorPos;

        // The color wheel consists of 6 sectors.
        // Figure out which sector you//re in.
        sectorPos = h / 60;
        sectorNumber = (int)(Math.Floor(sectorPos));

        // get the fractional part of the sector.
        // That is, how many degrees into the sector
        // are you?
        fractionalSector = sectorPos - sectorNumber;

        // Calculate values for the three axes
        // of the color.
        p = v * (1 - s);
        q = v * (1 - (s * fractionalSector));
        t = v * (1 - (s * (1 - fractionalSector)));

        // Assign the fractional colors to r, g, and b
        // based on the sector the angle is in.
        switch (sectorNumber)
        {
            case 0:
                r = v;
                g = t;
                b = p;
                break;

            case 1:
                r = q;
                g = v;
                b = p;
                break;

            case 2:
                r = p;
                g = v;
                b = t;
                break;

            case 3:
                r = p;
                g = q;
                b = v;
                break;

            case 4:
                r = t;
                g = p;
                b = v;
                break;

            case 5:
                r = v;
                g = p;
                b = q;
                break;
        }
    }
    // return an RGB structure, with values scaled
    // to be between 0 and 255.
    return Color.FromArgb((int)(r * 255), (int)(g * 255), (int)(b * 255));
}

Функция HSVtoRGB взята из https://bytes.com/topic/c-sharp/answers/236124-how-would-i-change-hue-bitmap, слегка скорректированный, поскольку исходная функция ожидает все входные данные как значения от 0 до 255, поэтому масштабирование должно быть удалено.

person cad    schedule 26.03.2016
comment
Небольшой совет, поскольку GetPixel ужасно медленный, возможно, сохраните его в переменной или, что еще лучше, используйте биты блокировки. - person Lonefish; 29.09.2016