だから私はGIMPのソースコードを調べました...ええと!私はそれを一般的で読みやすいものにしました。それでもかなり速いです。数学の説明については、Sampoの答えを参照してください。C#の実装は次のとおりです(C / C ++に簡単に変換可能):
static class PixelShaders {
/// <summary>
/// Generic color space color to alpha.
/// </summary>
/// <param name="pA">Pixel alpha.</param>
/// <param name="p1">Pixel 1st channel.</param>
/// <param name="p2">Pixel 2nd channel.</param>
/// <param name="p3">Pixel 3rd channel.</param>
/// <param name="r1">Reference 1st channel.</param>
/// <param name="r2">Reference 2nd channel.</param>
/// <param name="r3">Reference 3rd channel.</param>
/// <param name="mA">Maximum alpha value.</param>
/// <param name="mX">Maximum channel value.</param>
static void GColorToAlpha(ref double pA, ref double p1, ref double p2, ref double p3, double r1, double r2, double r3, double mA = 1.0, double mX = 1.0) {
double aA, a1, a2, a3;
// a1 calculation: minimal alpha giving r1 from p1
if (p1 > r1) a1 = mA * (p1 - r1) / (mX - r1);
else if (p1 < r1) a1 = mA * (r1 - p1) / r1;
else a1 = 0.0;
// a2 calculation: minimal alpha giving r2 from p2
if (p2 > r2) a2 = mA * (p2 - r2) / (mX - r2);
else if (p2 < r2) a2 = mA * (r2 - p2) / r2;
else a2 = 0.0;
// a3 calculation: minimal alpha giving r3 from p3
if (p3 > r3) a3 = mA * (p3 - r3) / (mX - r3);
else if (p3 < r3) a3 = mA * (r3 - p3) / r3;
else a3 = 0.0;
// aA calculation: max(a1, a2, a3)
aA = a1;
if (a2 > aA) aA = a2;
if (a3 > aA) aA = a3;
// apply aA to pixel:
if (aA >= mA / mX) {
pA = aA * pA / mA;
p1 = mA * (p1 - r1) / aA + r1;
p2 = mA * (p2 - r2) / aA + r2;
p3 = mA * (p3 - r3) / aA + r3;
} else {
pA = 0;
p1 = 0;
p2 = 0;
p3 = 0;
}
}
}
GIMPの実装(ここでは)はRGB色空間を使用し、0から1の範囲でアルファ値を使用し、0から255float
の範囲でR、G、Bを使用します。float
画像にJPEGアーティファクトがある場合、RGBの実装は見事に失敗します。これは、知覚できる色の偏差はわずかですが、絶対的なR、G、Bの偏差は非常に大きいためです。LAB色空間を使用すると、この場合のトリックを実行できます。
画像から無地の背景を削除するだけの場合は、カラーからアルファへのアルゴリズムは最適なオプションではありません。LAB色空間を使用して各ピクセルの色空間距離を計算すると、良い結果が得られました。計算された距離は、元の画像のアルファチャネルに適用されました。これとカラーからアルファへの主な違いは、ピクセルの色相が変更されないことです。背景の削除は、アルファ(不透明度)を色空間の差に設定するだけです。前景画像で背景色が発生しない場合にうまく機能します。その場合、背景を削除できないか、BFSアルゴリズムを使用して外側のピクセルのみを歩く必要があります(GIMPで魔法の杖の選択を使用してから選択を削除するなど)。
前景画像に背景色と同様の色の穴とピクセルの両方がある場合、背景を削除することはできません。このような画像は手動で処理する必要があります。