ディザノイズをクランプする適切な方法は何ですか?


9

2ビットノイズ(n =] 0.5,1.5 [およびoutput = floor(input *(2 ^ bits-1)+ n)を使用)で色深度とディザリングを減らす場合、値の範囲の終わり(入力0.0および1.0) )うるさい。それらを無地であることが望ましい。

例:https : //www.shadertoy.com/view/llsfz4

ノイズ勾配 (上記shadertoyのスクリーンショット、勾配を描き、両端であるべきで、それぞれ白と黒の固体であるが、代わりにノイズが多いです)

もちろん、問題は値の範囲を圧縮するだけで解決でき、両端が常に単一の値に丸められます。これは少しハックのように感じますが、これを「適切に」実装する方法があるかどうか疑問に思っていますか?


何らかの理由で、shadertoyが私のブラウザーで実行されませんでした。簡単な画像を投稿して、意味を説明していただけますか?
Simon F

1
n =]-1、1 [?
JarkkoL 2017年

@JarkkoLまあ、浮動小数点を整数に変換する式はoutput = floor(input * intmax + n)です。ここで、n = 0.5はノイズなしです(たとえば、> = 0.5で切り上げたいが<0.5で切り捨てたい)。これが、ノイズが0.5の「中心」にある理由です。
hotmultimedia 2017

@SimonFがシェーダートイの画像を追加
hotmultimedia 2017

1
(GPUのように)出力を丸めるのではなく切り捨てているようです-代わりに丸め、少なくとも適切な白を取得します:shadertoy.com/view/MlsfD7(image:i.stack.imgur.com/kxQWl.png
ミケル・ジョエル

回答:


8

TL; DR:2 * 1LSB triangle-pdfディザリングは、エッジケースの0と1でクランプにより中断します。解決策は、これらのエッジケースで1ビットの均一なディザーを許容することです。

2つ目の答えを追加します。これは、当初考えていたよりも少し複雑になったためです。この問題は「TODO:クランプが必要ですか?」2012年に正規化から三角ディザリングに切り替えてから、コードに追加しました。最後に確認してみてください:)投稿全体で使用されているソリューション/画像の完全なコード:https : //www.shadertoy.com/view/llXfzS

まず最初に、2 * 1LSB三角PDFディザリングを使用して信号を3ビットに量子化する場合の問題を次に示します。

出力 -基本的にhotmultimediaが示したもの。

コントラストが高くなると、質問で説明されている効果が明らかになります。エッジケースでは出力が平均して黒/白になりません(実際には、そうする前は0/1をはるかに超えています)。

ここに画像の説明を入力してください

グラフを見ると、もう少し洞察が得られます。

ここに画像の説明を入力してください (灰色の線は0/1を示し、灰色も出力しようとしている信号、黄色の線はディザリング/量子化された出力の平均、赤はエラー(信号平均)です)。

興味深いことに、平均出力が限界で0/1ではないだけでなく、線形ではありません(ノイズの三角確率密度分布によるものと思われます)。下端を見ると、出力が発散する理由は直感的に理解できます。ディザリングされた信号に負の値が含まれ始めると、出力のクランプにより、出力の低い方のディザリングされた部分の値(つまり負の値)が変化します。平均の値を増やします。図は正しいように見えます(均一で対称的な2LSBディザ、平均はまだ黄色):

ここに画像の説明を入力してください

ここで、1LSB正規化ディザを使用するだけであれば、エッジケースではまったく問題はありませんが、もちろん、三角ディザリングの優れた特性が失われます(たとえば、このプレゼンテーションを参照)。

ここに画像の説明を入力してください

(実用的、経験的)ソリューション(ハック)は、エッジケースの[-0.5; 0.5 [均一ディザリングに戻すことです。

float dithertri = (rnd.x + rnd.y - 1.0); //note: symmetric, triangular dither, [-1;1[
float dithernorm = rnd.x - 0.5; //note: symmetric, uniform dither [-0.5;0.5[

float sizt_lo = clamp( v/(0.5/7.0), 0.0, 1.0 );
float sizt_hi = 1.0 - clamp( (v-6.5/7.0)/(1.0-6.5/7.0), 0.0, 1.0 );

dither = lerp( dithernorm, dithertri, min(sizt_lo, sizt_hi) );

三角形のディザリングをそのまま残しながら、エッジケースを修正します。

ここに画像の説明を入力してください

だからあなたの質問に答えないでください:より数学的に固い解決策があるかどうかわからないので、Masters of Pastが何をしたかについても等しく知りたいと思っています:)それまで、少なくとも私たちはコードを機能させ続けるためにこの恐ろしいハックをします。

編集
私はおそらく、単に信号を圧縮することについて、質問で与えられた回避策の提案をカバーするべきです。エッジケースでは平均値が線形ではないため、入力信号を圧縮するだけでは完全な結果は得られませんが、エンドポイントは修正されます。 ここに画像の説明を入力してください

参考文献


エッジのラープが完璧に見える結果をもたらすことは驚くべきことです。私は少なくとも少しの逸脱を期待します:P
アランウルフ

うん、私も積極的に驚いた:)信号が減少しているのと同じ割合で、ディザの大きさを線形的に縮小しているので、うまくいくと思います。したがって、少なくともスケールは一致します...しかし、分布を直接ブレンドしても悪影響がないように見えるのは興味深いことです。
Mikkel Gjoel 2017

@MikkelGjoel残念ながら、コードのバグのため、あなたの信念は正しくありません。あなたは、どちらも同じRNG再利用dithertriおよびdithernorm独立した1の代わりに。すべての計算を終えてすべての条件を取り消すと、まったく容赦しなくなります。代わりに、コードはでのハードカットオフのように機能しv < 0.5 / depth || v > 1 - 0.5/depth、即座にそこで均一分布に切り替えます。それはあなたが持っている素晴らしいディザリングを奪うというわけではなく、それは単に不必要に複雑です。バグを修正することは実際に悪いです、あなたはより悪いディザーで終わるでしょう。ハードカットオフを使用するだけです。
orlp

さらに深く掘り下げた後、サンプルの平均化中にガンマ補正を行わない(線形でないsRGB空間で平均化する)シェーダートイに別の問題が見つかりました。ガンマを適切に処理すると、残念ながらまだ完了していないことがわかります。ガンマ補正を処理するには、ノイズを形成する必要があります。これは問題を表示しているシェーダートイです:shadertoy.com/view/3tf3Dn。いろいろと試してみましたが、うまくいきませんでしたので、computergraphics.stackexchange.com / questions / 8793 /…に質問を投稿しました。
orlp

3

私はあなたの質問に完全に答えられるかどうかわかりませんが、私はいくつかの考えを追加し、おそらく一緒に答えに到達することができます:)

まず、質問の根拠は私には少し不明確です。なぜ、他のすべての色にノイズがあるのに、黒/白をきれいにすることが望ましいと思うのですか?ディザリング後の理想的な結果は、完全に均一なノイズを持つ元の信号です。黒と白が異なる場合、ノイズは信号に依存します(とにかく色が固定される場所で発生するため、問題はないかもしれません)。

とは言っても、白または黒のいずれかにノイズがあると問題が発生する状況があります(私は、黒と白の両方を同時に「クリーン」にする必要があるユースケースを認識していません)。テクスチャの場合、クワッド全体にノイズを追加する必要はありません。テクスチャの外側にもノイズが表示されるためです。1つの解決策は、ノイズをオフセットすることです。そのため、[-0.5; 1.5 [を追加するのではなく、[-2.0; 0.0 [を追加します(つまり、2ビットのノイズを減算します)。これはかなり経験的な解決策ですが、私はもっと正しいアプローチを知りません。それについて考えると、失われた強度を補うために信号をブーストしたいと思うかもしれません...

ティモシーロッテス氏は、スペクトルの明るい部分のノイズを低減し、スペクトルの最も必要な部分にノイズをシェーピングすることについてGDCで話しました。http://32ipi028l5q82yhj72224m8j-wpengine.netdna-ssl.com/wp- content / uploads / 2016/03 / GdcVdrLottes.pdf


(申し訳ありませんが、誤ってEnterキーを押し、編集の時間制限が切れました)この例のユースケースは、重要な状況の1つです。3ビットのディスプレイデバイスで浮動小数点のグレースケールイメージをレンダリングします。ここでは、LSBを変更するだけで強度が大きく変化します。値の範囲を圧縮して終了値を飽和させるなど、終了値を無地の色にマップする「正しい方法」があるかどうかを理解しようとしています。そして、それの数学的説明は何ですか?例の数式では、1.0の入力値は平均7の出力を生成しません。これが私を困らせています。
hotmultimedia 2017

1

Mikkel Gjoelの三角ノイズによるディザリングのアイデアを、RNG呼び出しが1つだけ必要な単純な関数に簡略化しました。私はすべての不要なビットを取り除いたので、何が起こっているのかをかなり読みやすく、理解できるはずです。

// Dithers and quantizes color value c in [0, 1] to the given color depth.
// It's expected that rng contains a uniform random variable on [0, 1].
uint dither_quantize(float c, uint depth, float rng) {
    float cmax = float(depth) - 1.0;
    float ci = c * cmax;

    float d;
    if (ci < 0.5 || ci >= cmax - 0.5) {
        // Uniform distribution on [-0.5, 0.5] for edges.
        d = rng - 0.5;
    } else {
        // Symmetric triangular distribution on [-1, 1].
        d = (rng < 0.5) ? sqrt(2.0 * rng) - 1.0 : 1.0 - sqrt(2.0 - 2.0*rng);
    }

    return uint(clamp(ci + d + 0.5, 0.0, cmax));
}

アイデアとコンテキストについては、Mikkel Gjoelの回答を紹介します。


0

私はこの素晴らしい質問へのリンクと、shadertoyの例をたどりました。

提案された解決策についていくつか質問があります。

  1. 値vは何ですか?量子化したいのは0.0から1.0(黒から白)の範囲のRGB信号ですか?シングルフロートですか?(そうであれば、元のRGB信号からどのように計算しましたか?)
  2. 「マジックナンバー」0.5 / 7.0の出所は何ですか?ハーフビンだと思いますが、8ビットで表されるビンのサイズが1.0 / 255.0になると思いますので、0.5 / 0.7とびっくりしました。これらの数値をどのように導き出したか説明していただけませんか。何が欠けていますか?
  3. 三角形の分布が[-1,1]の範囲にあり、ユニフォームが[-0.5,0.5]にあると想定しています(「ハーフビット」は、エッジに近づいており、オーバーシュートしたくないためです。適用したロジック?)
  4. 一様および三角形の確率変数は独立している必要があります。私は正しいですか?

すごい仕事!私はあなたの考えを正しく理解したことを望んでいます。ありがとう!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.