13

透明な画像にボックス ブラーを適用しようとしていますが、エッジの周りに「暗いハロー」が表示されます。

Jerry Huxtableはこの問題について簡単に言及しており、問題が発生したことを示す非常に優れたデモがあります。

ここに画像の説明を入力

しかし、私の人生では、「事前に乗算されたアルファ」がどのように問題を解決できるかを理解できません。次に、非常に単純な例を示します。私は 1 つの赤と 1 つの緑のピクセルを含む 3x3 の画像を持っています。

ここに画像の説明を入力

実際には、残りのピクセルは透明です。

ここに画像の説明を入力

次に、画像に 3x3 ボックス ブラーを適用します。簡単にするために、中央のピクセルの新しい値のみを計算します。ボックス ブラーが機能する方法は、9 位置の正方形 (カーネルと呼ばれる 3x3) があるため、カーネル内の各ピクセルの 1/9 を取得し、それを合計することです。

ここに画像の説明を入力

そう

finalRed =   1/9 * red1 + 1/9 * red2 + 1/9 * red3+ ... + 1/9 * red9
finalGreen = 1/9*green1 + 1/9*green2 + 1/9*green3+ ... + 1/9*green9
finalBlue =  1/9* blue1 + 1/9* blue2 + 1/9* blue3+ ... + 1/9* blue9
finalAlpha = 1/9*alpha1 + 1/9*alpha2 + 1/9*alpha3+ ... + 1/9*alpha9

この非常に単純化された例では、計算は非常に単純になります。

finalRed =   1/9 * 255
finalGreen = 1/9 * 255
finalBlue =  0
finalAlpha = 1/9*255 + 1/9*255

これにより、次の最終的な色の値が得られます。

finalRed =   28
finalGreen = 28
finalBlue =  0
finalAlpha = 56 (22.2%)

ここに画像の説明を入力

この色は暗すぎる。Photoshop で同じ 3x3 ピクセルの画像に対して 3px ボックス ブラーを実行すると、次のような結果が得られます。

ここに画像の説明を入力

白の上に表示すると、どちらがより明確になります:

ここに画像の説明を入力


実際には、透明なテキストを含むビットマップでボックスぼかしを実行しています。テキストは、フリンジの周りが暗くなっています。

ここに画像の説明を入力

私はPixelFormat32bppARGBフォーマットされているGDI +ビットマップから始めています


3x3 畳み込みカーネルを適用するときに「事前に乗算されたアルファ」を使用するにはどうすればよいですか?

次の理由から、回答には新しいフォーラムを含める必要があります。

final = 1/9*(pixel1+pixel2+pixel3...+pixel9)

間違った答えを得ています。


編集:より簡単な例は次のとおりです。

0..1 の範囲の色とアルファ値でこの計算を実行します。

ここに画像の説明を入力

ボックス ブラー畳み込みフィルターを中央のピクセルに適用します。

ARGB'
      = 1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0) + 
        1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0) + 
        1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0);

      = (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0) +
        (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0) +
        (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0)

      = (0, 0.33, 0, 0.33)

これにより、かなり透明な濃い緑色が得られます。

ここに画像の説明を入力

これは私が期待するものではありません。比較すると、Photoshop の Box Blur は次のようになります。

ここに画像の説明を入力

事前に乗算されたアルファであると想定(0, 0.33, 0, 0.33)し、乗算を解除すると、次のようになります。

(0, 1, 0, 0.33)

ここに画像の説明を入力

これは、私の完全に不透明な例に適しています。しかし、部分的に透明なピクセルを使用し始めたときにどうすればよいかわかりません。

こちらもご覧ください

4

3 に答える 3

7

tkerwin はすでに正解を提供していますが、さらに説明が必要なようです。

質問で示した数学は、最後まで完全に正しいです。ステップが欠けているのはそこです - 結果はまだ事前に乗算されたアルファモードにあり、 PixelFormat32bppARGB 形式に「乗算されていない」必要があります。乗算の反対は除算です。したがって、次のようになります。

finalRed = finalRed * 255 / finalAlpha;
finalGreen = finalGreen * 255 / finalAlpha;
finalBlue = finalBlue * 255 / finalAlpha;

あなたは、除算によって極端に範囲外の結果が生じるかもしれないという懸念を表明しましたが、それは起こりません。数学をたどると、乗算前のステップのため、赤、緑、青の値がアルファ値を超えることはできないことがわかります。単純なボックス ブラーよりも複雑なフィルターを使用している場合は可能性がありますが、アルファを使用していない場合でも同様です。正しい応答は、結果をクランプして、負の数を 0 に、255 より大きいものを 255 に変えることです。

于 2011-02-03T18:04:31.013 に答える
2

リンクのアドバイスに従って、ぼかしの前に事前に乗算し、ぼかしの後に事前に乗算を解除します。あなたの例では、半透明のピクセルがないため、事前乗算は実際には何もしません。ぼかしを行った後、事前乗算を解除する必要があります (0 から 1 の正規化されたカラー値を想定)。

RGB' = RGB/A  (if A is > 0)
A' = A

これにより、乗算前のぼやけた最終画像が得られます。

于 2011-01-31T19:27:13.760 に答える
0

正しい数学、間違った演算

ここでは両方の答えが間違っているように見えますが、あなたの例では正しい計算ができましたが、過剰操作ではありません。

Porter Duff によると、次のような適切な配合処方を使用してください。

FG.RGB + (1.0 - FG.Alpha)*BG.RGB

残りの答えがどこから来ているのかはわかりませんが、うわー。

アルファ エンコーディングは、オーバー オペレーションを指示します

適切にエンコードされた場合、RGBA はエミッションとオクルージョンを表します

画像にアルファを関連付ける必要がある理由は、RGB 値が常に発光を表すためです。この場合、RGB はピクセルの発光を表し、アルファはオクルージョンの度合いを表します。

つまり、ボックス ブラーのように線形に補間する場合、値は放出を示す必要があります。最も単純なケースでは、100% 発光するピクセルを考えて、増分ごとに 25% ずつ線形補間します。

ここでは、100%、75%、50%、25%、最後に 0% になるように、各 RGB の発光が 25% 減少するはずです。各インクリメントで、アルファが同じ値で完全に同期したままになるように、放出はオクルージョンの程度に応じてスケーリングされることに注意してください。放射とオクルージョンの 1 つの単位として RGBA 全体に畳み込みを適用するだけです。最も重要なことは、ブレンド式がこの回答の最初のものでなければならないということです。

次に、実際にはまったくエンコードされていない関連付けられていないアルファのケースを考えてみましょう。ここでは、放出はオクルージョンの程度とはまったく関連していないため、over 操作は、放出のスケーリングを最初のステップにバンドルし、関連付けられていない放出にオクルージョンの程度を乗算します。

FG.RGB * FG.A + (1.0 - FG.A) BG.RGB

しかし、完全にエンコードされていない値に対して、まったく同じ線形補間、回転、ぼかし、ぼかし、またはその他の操作を誰かが愚かにも実行しようとするとどうなりますか? では、見てみましょう...

関連付けられていないアルファの例では、放出は 100% ですが、オクルージョンの度合いは 75% です。ここで、25% で補間します。ここで、光輸送の基本的な計算がどのように失敗するかに注目してください。最終的には、放出と完全に同期していないアルファ表現になってしまいます。100%RGB-75%A、75%RGB-56.25%A、50%RGB-28.125%A など

でも待って、もっと闇がある...

パズルの最後のピースは、非線形にエンコードされた表示参照値を使用していることです。つまり、sRGB ディスプレイ用にエンコードされた値を使用する場合、値は非線形に圧縮され、ディスプレイの EOTF によって元に戻され、ディスプレイからの線形光出力に戻されます。つまり、私たちのコード値は、ディスプレイから放射される放射測定のような比率を表していません。そのため、圧縮された MP3 値でオーディオ計算を実行すると失敗するのとほぼ同じように、放出とオクルージョンの線形計算は失敗します。

したがって、単純な線形補間の例では、数学が根本的にすぐに崩壊することがわかります。

最初の増分は 100% の排出量で、2 番目の増分は 75% というようになります。しかし、sRGB 非線形エンコード値を使用して 100% から 25% に線形補間すると、実際に放出される光の量はこの単純な計算から切り離され、関連付けられていないアルファ エンコーディングがバラバラになった方法と非常によく似た方法でアルファが縞模様になります。 . これを回避する唯一の方法は、プロセスを 3 つのステップにすることです。

  1. ピクセルの非線形圧縮 sRGB 伝達関数を元に戻します。
  2. 計算を実行します。
  3. 宛先伝達関数 (この場合は sRGB) に従って非線形 sRGB エンコーディングを再適用します。

正しい答え、間違った公式

繰り返しますが、ボックス ブラーの計算は、最初のインスタンスでは十分に正しく、半透明のグリーンは 33% の放射で、アルファ オクルージョンは 33% でした。根本的な問題は、上記の式であるオーバー オペレーションでした。つまり、フル発光のバックグラウンドを超える緑色の場合は、次のようになります。

  FG.RGB + (1.0 - FG.A) * BG.RGB
  [0.0 0.33 0.0] + ((1.0 - 0.33) * [1.0 1.0 1.0])
  [0.0 0.33 0.0] + [0.77 0.77 0.77]
  [0.77 1.0 0.77]

ただし、例を 100% の sRGB 赤色発光に合成すると、適切な計算を行っても、放射分析でエンコードされていない値のために、より暗い結果が得られることに注意してください。sRGB の緑と赤の選択は、発生する非線形の数学的な暗さを悪化させる完璧な例です。特に、完全に発光する緑の背景の上で赤のオブジェクトにぼかしを実行する場合はそうです。以下は、計算に非線形圧縮された sRGB コード値を使用していますが、完全に正しく合成されています。 悪い星

追加資料

関連する引用をいくつか。まず、Autodesk の Zap Andersson による、悪名高い Adob​​e Alpha スレッドで、アルファ チャネルの作成者である Alvy Ray Smith によって確認されました。

ここでの誤りは、Chris が "Premultiplied" という言葉を文字通りに解釈していることです。多くの人がそうしていますが、間違っています。実際、私はこの言葉が本当に嫌いです。なぜなら、それが文字通りの意味であると信じ込ませてしまうからです。それは間違いです。これは、「事前乗算」の意味を完全に誤解しています。

アカデミーの科学的および技術的業績の勝者、ラリー・グリッツ:

この時点で、私は少し宗教的な暴言を吐き出し、関連付けられたアルファ (事前乗算された色) が理にかなっている唯一の選択肢であるとだけ言います。これは、レンダラーが自然に生成する可能性が高い唯一のものであり、合成やその他の画像処理の数学が機能する唯一の方法であり、私の意見では、画像を保存するための唯一の賢明な形式です。

関連付けられたアルファは、関連付けられていないアルファ (事前に乗算されていない色) では表現できない RGBA 値を表現できることにも注意してください。それはただの人生の事実です

(グリッツ氏がここで彼の CANNOT ステートメントで言及しているものの例は、オクルージョンがなく発光のみの炎や反射のようなものの場合、またはアルファがゼロの RGB の場合です。これは基本的に、関連付けられていないアルファ操作。)

Academy Scientific and Technical Achievement の受賞者 Jeremy Selan :

まず第一に、私は事前乗算の「プロ」です。私の理解では、事前乗算はアルファ付きのピクセルの自然な表現です。それについての大きな紛らわしさは名前です。

于 2019-06-16T20:53:31.580 に答える