C#颜色混合和计算透明度/alpha值类似于Photoshop

3
我有一张图片需要处理,使其呈现非常特定的外观。我在 Photoshop 中找到了一个教程,并逐步重现了它的效果。最新的效果是一种颜色混合模式,我已经成功地实现了它,但是他们添加了一个 alpha 值,这让我感到困惑。
Photoshop 通过创建滤镜、设置颜色、选择“混合”并应用 alpha 值来实现。Alpha 值应用于滤镜而不是基本图像。
我的做法是将基本图像和叠加的颜色两个颜色转换为 HSL 颜色空间,然后进行混合。我从叠加的颜色中取出 Hue/Saturation 值,从基本图像中取出 Luminosity 值,并创建一个新的 HSL 颜色进行混合。我然后将其转换为 RGB 并在原始基础颜色上写入该像素。
我不知道如何应用 alpha 值。我觉得应该取基本颜色和混合值的乘积,然后计算它们之间的 alpha 值。但我不确定这是否正确,或在哪里可以找到正确的颜色计算方法。
我认为这个问题不需要代码,但如果需要,我可以贴一些代码。
谢谢。

糟糕,我的错!我刚刚找到了方程式,现在一切都像魔法般运作!https://dev59.com/cHRB5IYBdhLWcg3wAjXR下次我会更仔细地搜索! - Terrordoll
1个回答

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之间,所以必须去除缩放。

1
小技巧,由于GetPixel非常慢,也许可以将其保存在变量中,或者更好的方法是使用lockbits。 - Lonefish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接