8

Gimpの「ColortoAlpha」機能にまだ慣れていない人のために、Gimpのドキュメントからのページがここにあります:ColortoAlpha。それは本当に良い仕事をします、そして私は色がどんな色空間にあっても、色操作に関してGimpがそれをどれほど正確に行うのか疑問に思います。ヒントをたくさんありがとう。

編集1:キーカラー([カラーからアルファ]ダイアログで選択したもの)との類似性に基づいてピクセルの透明度情報を生成することは、何らかの理由で答えを削除する前に提案されたように、良い洞察のように聞こえます、しかしそれよりも複雑だと思います。単位範囲0.0〜1.0で色の類似性を推定し、たとえば、白の色に似た色、たとえば0.4のピクセルがあるとします(「色アルファ」ダイアログ)、したがってピクセルは0.6のアルファ値を取得します。次に、結果のピクセルがアルファ0.6の白い背景に対して表示されるときに、明るさ/明るさ/彩度の緩みを補正するために、ピクセルの実際の色をどのように変更しますか?

編集2:実際の更新:最初の編集に関連するサブ質問は、結果の色を変更せずにピクセルのアルファを変更する方法で回答されていますか?しかし、「Color to Alpha」機能のGimpのソースで行われていることはそれほど単純ではなく、数式ではなく特定のアルゴリズムに基づいているように見えるため、おそらく完全な話ではありません。

4

5 に答える 5

10

ソースコードを見てみましたが、その要はcolortoalpha関数です。パラメータ*a1〜 * a4は、それぞれ入力/出力の赤、緑、青、アルファであり、c1〜c3はアルファを作成するための色です。

2つの色c1とc2を特定のアルファa(0≤a≤1)と組み合わせると、結果は次のようになります。

y = a * c1 + (1-a) * c2

ここでは逆の操作を行っています。最終結果yと背景色c2がわかっているので、c1とaを計算します。これは指定不足の方程式であるため、解は無限にあります。ただし、0≤c1≤255および0≤a≤1の範囲は、解に限界を追加します。

Gimpプラグインが機能する方法は、ピクセルごとにアルファ値を最小化する(つまり、透明度を最大化する)ことです。逆に、これは、完全に透明ではない(つまり、正確に背景色ではなかった)結果のピクセルごとに、RGBコンポーネントの1つが0または255のいずれかであることを意味します。

これにより、指定された色の上にオーバーレイすると、元の画像が生成され(丸め誤差がない場合)、各ピクセルの透明度が最大になる画像が生成されます。

プロセス全体がRGB色空間で実行されることは注目に値しますが、結合操作が同じ色空間で実行される限り、他の色空間でも実行できます。

于 2013-02-16T21:39:16.507 に答える
2

このフィルターをエディターwww.Photopea.comの[フィルター]-[その他]-[カラーからアルファ]に実装しました。結果はGIMPと100%同じです。アルゴリズムは非常に単純です。

アイデア:透明度の値Aを使用して、背景色Bを前景色Fと組み合わせて、新しい色Nを取得します。

N = A * F  +  (1 - A) * B;

N(画像の実際の色)とB(フィルターのパラメーター)がわかっていて、前景色Fとその透明度Aを復元したいとします。

このようにしてください:

A = max( abs(N.r - B.r), abs(N.g - B.g), abs(N.b - B.b)  )  

これで、N、B、Aがわかりました。上記の式を使用してFを計算してください。

于 2020-06-11T21:56:08.403 に答える
1

色の類似性を比較するためのメカニズムを考え出す必要があります。これを行うことができるさまざまな色空間があります。RGBは、この種のものには最適ではないことがよくあります。ただし、HSV、YCbCr、またはその他のルーマ/クロマスペースを使用することもできます。多くの場合、これらのスペースの1つでの距離は、RGBでのユークリッド距離よりも良い答えを提供します。距離が決まったら、それを最大距離で割ってパーセンテージを得ることができます。そのパーセンテージは、1つの可能性として、使用するアルファの逆になります。

GIMPがどのようにそれを行うかを知りたい場合は、ソースを見ることができます。たとえば、そのプラグインに対する最近のコード変更が1つあります。

于 2012-02-16T20:52:59.217 に答える
1

だから私は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で魔法の杖の選択を使用してから選択を削除するなど)。

前景画像に背景色と同様の色の穴とピクセルの両方がある場合、背景を削除することはできません。このような画像は手動で処理する必要があります。

于 2016-11-29T09:49:53.243 に答える
0

colortoalphaメソッドをgimpからC#に可能な限り変換しました。問題は、RGBA値がImageSharpのようなライブラリの各チャネルのバイトとして取得されることです。一部の変換では変換中にデータが失われますが、できる限り保持するように最善を尽くしました。これは、画像の変更にImageSharpを使用します。ImageSharpは完全に管理されているため、プラットフォーム間で機能します。そのまた速い。このメソッド全体は、約10ミリ秒(10ミリ秒未満)で実行されます。

C#実装のコードは次のとおりです。

public static unsafe void ColorToAlpha(this Image<Rgba32> image, Rgba32 color)
    {
        double alpha1, alpha2, alpha3, alpha4;
        double* a1, a2, a3, a4;

        a1 = &alpha1;
        a2 = &alpha2;
        a3 = &alpha3;
        a4 = &alpha4;

        for (int j = 0; j < image.Height; j++)
        {
            var span = image.GetPixelRowSpan(j);

            for (int i = 0; i < span.Length; i++)
            {
                ref Rgba32 pixel = ref span[i];

                // Don't know what this is for
                // *a4 = pixel.A;

                if (pixel.R > color.R)
                    *a1 = (pixel.R - color.R) / (255.0 - color.R);
                else if (pixel.R < color.R)
                    *a1 = (color.R - pixel.R) / color.R;
                else
                    *a1 = 0.0;

                if (pixel.G > color.G)
                    *a2 = (pixel.G - color.G) / (255.0 - color.G);
                else if (pixel.G < color.G)
                    *a2 = (color.G - pixel.G) / color.G;
                else
                    *a2 = 0.0;

                if (pixel.B > color.B)
                    *a3 = (pixel.B - color.B) / (255.0 - color.B);
                else if (pixel.B < color.B)
                    *a3 = (color.B - pixel.B) / color.B;
                else
                    *a3 = 0.0;

                if (*a1 > *a2)
                    *a4 = *a1 > *a3 ? *a1 * 255.0 : *a3 * 255.0;
                else
                    *a4 = *a2 > *a3 ? *a2 * 255.0 : *a3 * 255.0;

                if (*a4 < 1.0)
                    return;

                pixel.R = (byte)Math.Truncate((255.0 * (*a1 - color.R) / *a4 + color.R));
                pixel.G = (byte)Math.Truncate((255.0 * (*a2 - color.G) / *a4 + color.G));
                pixel.B = (byte)Math.Truncate((255.0 * (*a3 - color.B) / *a4 + color.B));

                pixel.A = (byte)Math.Truncate(*a4);
            }
        }
    }
于 2018-09-04T15:54:00.897 に答える