Photoshop中的色相/饱和度调整层算法

时间:2010-12-10 00:17:08

标签: image-processing colors photoshop rgb hsl

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

或者是否可以使用适当设置的混合模式(多重,屏幕,色调,饱和度,颜色,亮度......)将Hue /饱和度调整图层替换为普通图层? 如果是,那怎么样?

由于

6 个答案:

答案 0 :(得分:9)

当选中“Colorize”复选框时,我对的计算进行了逆向工程。以下所有代码均为伪代码

输入是:

  • hueRGB ,这是HSV(photoshop_hue, 100, 100).ToRGB()
  • RGB颜色
  • 饱和度,即photoshop_saturation / 100.0(即0..1)
  • 亮度,即photoshop_lightness / 100.0(即-1..1)
  • value ,即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

答案 1 :(得分: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等

if (h >= 45 && h < 75)
        s += s * yellow_percent;

还有其他可能性,例如应用衰减滤波器,如:

/* For h=60, let m=1... and linearly fall off to h=75 m=0. */
m = 1 - abs(h - 60) / 15;
if (m < 0)
        m = 0;
s += s * yellow_percent * d;

答案 2 :(得分:3)

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

输入参数亮度 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

但是,如果您选择一些间隔(例如Reds而不是Master),Lightness表现完全不同,更像饱和度。

答案 3 :(得分:1)

您好我写了着色着色器,我的等式如下:

inputRGB是应该是单色的源图像

(r+g+b) * 0.333

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

伪代码:

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

我认为它快速有效

答案 4 :(得分:0)

选中“着色”复选框时,底层的亮度与色相和饱和度滑块的值组合,并根据{{3的等式从HSL转换为RGB。 }。 (亮度滑块只是将亮度重新映射到刻度的一个子集,正如您在观看直方图时看到的那样;效果非常糟糕,我不明白为什么有人会使用它。)

答案 5 :(得分:0)

我确实将@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;
    }

}