【问题标题】:Algorithm for Hue/Saturation Adjustment Layer from PhotoshopPhotoshop 中的色相/饱和度调整图层算法
【发布时间】:2011-05-23 05:09:54
【问题描述】:

有人知道调整图层在 Photoshop 中的工作原理吗?我需要从色相/饱和度调整层生成具有源图像和 HSL 值的结果图像。转换为 RGB,然后与源颜色相乘不起作用。

或者是否可以将色相/饱和度调整图层替换为具有适当设置的混合模式(倍增、屏幕、色相、饱和度、颜色、亮度……)的普通图层? 如果是那怎么办?

谢谢

【问题讨论】:

    标签: image-processing colors photoshop rgb hsl


    【解决方案1】:

    我对选中“着色”复选框的计算进行了逆向工程。以下所有代码都是伪代码

    输入是:

    • hueRGB,这是HSV(photoshop_hue, 100, 100).ToRGB()RGB 颜色
    • 饱和度,即photoshop_saturation / 100.0(即0..1)
    • 亮度,即photoshop_lightness / 100.0(即-1..1)
    • ,即pixel.ToHSV().Value,缩放到0..1范围。

    给单个像素上色的方法:

    color = blend2(rgb(128, 128, 128), hueRGB, saturation);
    
    if (lightness <= -1)
        return black;
    else if (lightness >= 1)
        return white;
    
    else if (lightness >= 0)
        return blend3(black, color, white, 2 * (1 - lightness) * (value - 1) + 1)
    else
        return blend3(black, color, white, 2 * (1 + lightness) * (value) - 1)
    

    blend2blend3 分别是:

    blend2(left, right, pos):
        return rgb(left.R * (1-pos) + right.R * pos, same for green, same for blue)
    
    blend3(left, main, right, pos):
        if (pos < 0)
            return blend2(left, main, pos + 1)
        else if (pos > 0)
            return blend2(main, right, pos)
        else
            return main
    

    【讨论】:

    • 太好了,谢谢分享。我玩过你的代码,结果似乎比预期的要亮一点。然后我意识到它的发生是因为这条线 2 * (1 + lightness) * (value) - 1 如果我们不将 (1 + lightness) * (value) 与 2 相乘,问题就解决了。
    • 第一行的rgb(128, 128, 128) 是什么?原始单个像素的颜色 rgb?
    • @zwcloud 这只是灰色#808080
    【解决方案2】:

    我已经弄清楚 Lightness 的工作原理。

    输入参数亮度b在[0, 2],输出为c(颜色通道)。

    if(b<1) c = b * c;
    else    c = c + (b-1) * (1-c);
    

    一些测试:

    b = 0  >>>  c = 0  // black
    b = 1  >>>  c = c  // same color
    b = 2  >>>  c = 1  // white
    

    但是,如果您选择某个间隔(例如,红色而不是 Master),亮度的表现完全不同,更像是饱和度。

    【讨论】:

    • 对于 b > 1,我认为 c = 1 - (2-b) * (1-c) 更有意义。 @Ivan Kuckir
    • 这两个公式会得到相同的结果
    【解决方案3】:

    Photoshop,不知道。但理论通常是:RGB图像通过特定层的内部方法转换为HSL/HSV;然后根据指定的参数修改每个像素的HSL,并将如此获得的结果以RGB形式返回(用于显示)。

    PaintShopPro7 用于以 30° (IIRC) 的离散增量分割 H 空间(假设范围为 0..360),因此如果您仅碰撞“黄色”,即仅 H 分量值为 45 的像素-75 将被视为操纵。

    红色 345..15,橙色 15..45,黄色 45..75,黄绿色 75..105,绿色 105..135,等等。

    如果 (h >= 45 && h

    还有其他可能性,例如应用衰减过滤器,如下所示:

    /* 对于 h=60,让 m=1... 并线性下降到 h=75 m=0。 */ m = 1 - abs(h - 60) / 15; 如果 (m

    【讨论】:

      【解决方案4】:

      你好,我写了着色着色器,我的方程式如下

      inputRGB 是源图像,应该是单色的

      (r+g+b) * 0.333
      

      colorRGB 是您的目标颜色
      finalRGB 是结果

      伪代码:

      finalRGB = inputRGB * (colorRGB + inputRGB * 0.5);
      

      我认为它快速高效

      【讨论】:

        【解决方案5】:

        如果有人需要,我确实将@Roman Starkov 的解决方案翻译成 java,但由于某种原因它效果不佳,然后我开始阅读一点,发现解决方案非常简单,有两件事必须是完成:

        1. 当更改色调或饱和度时,仅替换原始图像的色调和饱和度,亮度保持原样,这种混合方法称为 10.2.4。亮度混合模式: https://www.w3.org/TR/compositing-1/#backdrop

        2. 在 Photoshop 中更改亮度时,滑块指示我们需要在原始亮度中添加或减去多少百分比才能在 HSL 中获得白色或黑色。

        例如: 如果原始像素是 0.7 亮度并且亮度滑块 = 20 所以我们需要更多的 0.3 亮度才能达到 1

        所以我们需要添加到原始像素亮度:0.7 + 0.2*0.3; 这将是新像素的新混合亮度值。

        @Roman Starkov 解决方案 Java 实现:

        //newHue, which is photoshop_hue (i.e. 0..360)
        //newSaturation, which is photoshop_saturation / 100.0 (i.e. 0..1)
        //newLightness, which is photoshop_lightness / 100.0 (i.e. -1..1)
        
        //returns rgb int array of new color
        private static int[] colorizeSinglePixel(int originlPixel,int newHue,float newSaturation,float newLightness)
        {
            float[] originalPixelHSV = new float[3];
            Color.colorToHSV(originlPixel,originalPixelHSV);
            float originalPixelLightness = originalPixelHSV[2];
        
            float[] hueRGB_HSV = {newHue,100.0f,100.0f};
            int[] hueRGB = {Color.red(Color.HSVToColor(hueRGB_HSV)),Color.green(Color.HSVToColor(hueRGB_HSV)),Color.blue(Color.HSVToColor(hueRGB_HSV))};
        
        
            int color[] = blend2(new int[]{128,128,128},hueRGB,newSaturation);
            int blackColor[] = new int[]{Color.red(Color.BLACK),Color.green(Color.BLACK),Color.blue(Color.BLACK)};
            int whileColor[] = new int[]{Color.red(Color.WHITE),Color.green(Color.WHITE),Color.blue(Color.WHITE)};
        
            if(newLightness <= -1)
            {
                return blackColor;
            }
            else if(newLightness >=1)
            {
                return whileColor;
            }
            else if(newLightness >=0)
            {
                return blend3(blackColor,color,whileColor, (int) (2*(1-newLightness)*(originalPixelLightness-1) + 1));
            }
            else
            {
                return blend3(blackColor,color,whileColor, (int) ((1+newLightness)*(originalPixelLightness) - 1));
            }
        }
        
        private static int[] blend2(int[] left,int[] right,float pos)
        {
            return new int[]{(int) (left[0]*(1-pos)+right[0]*pos),(int) (left[1]*(1-pos)+right[1]*pos),(int) (left[2]*(1-pos)+right[2]*pos)};
        }
        
        private static int[] blend3(int[] left,int[] main,int[] right,int pos)
        {
            if(pos < 0)
            {
                return blend2(left,main,pos+1);
            }
            else if(pos > 0)
            {
                return blend2(main,right,pos);
            }
            else
            {
                return main;
            }
        
        }
        

        【讨论】:

          【解决方案6】:

          选中“着色”复选框时,下层的亮度与色相和饱和度滑块的值相结合,并根据https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSL 处的公式从 HSL 转换为 RGB . (亮度滑块只是将亮度重新映射到比例的子集,从直方图可以看出;效果非常糟糕,我不明白为什么有人会使用它。)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-10-10
            • 1970-01-01
            • 2012-12-31
            • 1970-01-01
            • 2015-12-29
            • 2012-03-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多