ImageMagick を使用して、Photoshop のカラー ブレンド モードを複製しようとしています。オンライン ガイドで次の数式を見つけましたが、その意味がわかりません。特定のチャンネルを交換するだけでよいですか?
4 に答える
少し前に、Photoshop の描画モードをリバース エンジニアリングしました。
ここを見てください:
http://www.kineticsystem.org/?q=node/13
以下は、HSY (色相、彩度、明度) と RGB (赤、緑、青) の間の変換に使用するコードです。Photoshop は、彩度を計算するために Hexacones と呼ばれるものを使用します。
ジョバンニ
/**
* This is the formula used by Photoshop to convert a color from
* RGB (Red, Green, Blue) to HSY (Hue, Saturation, Luminosity).
* The hue is calculated using the exacone approximation of the saturation
* cone.
* @param rgb The input color RGB normalized components.
* @param hsy The output color HSY normalized components.
*/
public static void rgbToHsy(double rgb[], double hsy[]) {
double r = Math.min(Math.max(rgb[0], 0d), 1d);
double g = Math.min(Math.max(rgb[1], 0d), 1d);
double b = Math.min(Math.max(rgb[2], 0d), 1d);
double h;
double s;
double y;
// For saturation equals to 0 any value of hue are valid.
// In this case we choose 0 as a default value.
if (r == g && g == b) { // Limit case.
s = 0d;
h = 0d;
} else if ((r >= g) && (g >= b)) { // Sector 0: 0° - 60°
s = r - b;
h = 60d * (g - b) / s;
} else if ((g > r) && (r >= b)) { // Sector 1: 60° - 120°
s = g - b;
h = 60d * (g - r) / s + 60d;
} else if ((g >= b) && (b > r)) { // Sector 2: 120° - 180°
s = g - r;
h = 60d * (b - r) / s + 120d;
} else if ((b > g) && (g > r)) { // Sector 3: 180° - 240°
s = b - r;
h = 60d * (b - g) / s + 180d;
} else if ((b > r) && (r >= g)) { // Sector 4: 240° - 300°
s = b - g;
h = 60d * (r - g) / s + 240d;
} else { // Sector 5: 300° - 360°
s = r - g;
h = 60d * (r - b) / s + 300d;
}
y = R * r + G * g + B * b;
// Approximations erros can cause values to exceed bounds.
hsy[0] = h % 360;
hsy[1] = Math.min(Math.max(s, 0d), 1d);
hsy[2] = Math.min(Math.max(y, 0d), 1d);
}
/**
* This is the formula used by Photoshop to convert a color from
* HSY (Hue, Saturation, Luminosity) to RGB (Red, Green, Blue).
* The hue is calculated using the exacone approximation of the saturation
* cone.
* @param hsy The input color HSY normalized components.
* @param rgb The output color RGB normalized components.
*/
public static void hsyToRgb(double hsy[], double rgb[]) {
double h = hsy[0] % 360;
double s = Math.min(Math.max(hsy[1], 0d), 1d);
double y = Math.min(Math.max(hsy[2], 0d), 1d);
double r;
double g;
double b;
double k; // Intermediate variable.
if (h >= 0d && h < 60d) { // Sector 0: 0° - 60°
k = s * h / 60d;
b = y - R * s - G * k;
r = b + s;
g = b + k;
} else if (h >= 60d && h < 120d) { // Sector 1: 60° - 120°
k = s * (h - 60d) / 60d;
g = y + B * s + R * k;
b = g - s;
r = g - k;
} else if (h >= 120d && h < 180d) { // Sector 2: 120° - 180°
k = s * (h - 120d) / 60d;
r = y - G * s - B * k;
g = r + s;
b = r + k;
} else if (h >= 180d && h < 240d) { // Sector 3: 180° - 240°
k = s * (h - 180d) / 60d;
b = y + R * s + G * k;
r = b - s;
g = b - k;
} else if (h >= 240d && h < 300d) { // Sector 4: 240° - 300°
k = s * (h - 240d) / 60d;
g = y - B * s - R * k;
b = g + s;
r = g + k;
} else { // Sector 5: 300° - 360°
k = s * (h - 300d) / 60d;
r = y + G * s + B * k;
g = r - s;
b = r - k;
}
// Approximations erros can cause values to exceed bounds.
rgb[0] = Math.min(Math.max(r, 0d), 1d);
rgb[1] = Math.min(Math.max(g, 0d), 1d);
rgb[2] = Math.min(Math.max(b, 0d), 1d);
}
ウィキペディアには、ブレンド モードに関する優れた記事があります http://en.wikipedia.org/wiki/Blend_modes
これらは、乗算、スクリーン、およびオーバーレイ モードの式を示します。
Multiply
Formula: Result Color = (Top Color) * (Bottom Color) /255
Screen
Formula: Result Color = 255 - [((255 - Top Color)*(255 - Bottom Color))/255]
Overlay
Formula: Result Color = if (Bottom Color < 128)
then (2 * Top Color * Bottom Color / 255)
else (255 - 2 * (255 - Top Color) * (255 - Bottom Color) / 255)
Aは前景ピクセル、Bは背景ピクセル、Cは新しいピクセルです。Hは各ピクセルの色相値、Sは彩度値、Lは輝度値、Yは明るさの値です。(ただし、輝度と明るさの違いはわかりません。
とにかく、最初の例では、新しいピクセル(C)の色相(H)と彩度(S)の値が前景ピクセル(A)からコピーされ、新しいピクセルの明るさ(Y)値が輝度( L)Background(B)ピクセルの値。
アルファ チャネルも組み込む必要がある場合、これらのカラー ブレンディング フォーミュラは非常に扱いにくいものです。Photoshop のブレンドを再現できませんでしたが、Gimp は次のように動作します。
Color mix_hsv(
ColorMixMode::Enum mode, // blending mode
Color cd, // destination color (bottom pixel)
Color cs) // source color (top pixel)
{
// Modify the source color
float dh, ds, dv; // destination hsv
float sh, ss, sv; // source hsv
cd.GetHsv(dh, ds, dv);
cs.GetHsv(sh, ss, sv);
switch (mode) {
case HUE: cs.InitFromHsv(sh, ds, dv); break;
case SATURATION: cs.InitFromHsv(dh, ss, dv); break;
case COLOR: cs.InitFromHsv(sh, ss, dv); break;
case LUMINOSITY: cs.InitFromHsv(dh, ds, sv); break;
}
cs.A = std::min(cd.A, cs.A);
// Blend the modified source color onto the destination color
unsigned char cd_A_orig = cd.A;
cd = mix(NORMAL, cd, cs); // normal blending
cd.A = cd_A_orig;
return cd;
}
事前に乗算されたアルファを使用する場合は、上記のコードで正しく処理することを忘れないでください。Gimp のソース コードにブレンドするためのコードを見つけることができませんでしたが、結果のイメージは非常に似ています。
Photoshop のカラー ブレンディングは明らかに違うので、誰かがそれを実装する方法を見つけたら、私たち全員に知らせてください :o)
味噌