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が何をしたかについても等しく知りたいと思っています:)それまで、少なくとも私たちはコードを機能させ続けるためにこの恐ろしいハックをします。
編集
私はおそらく、単に信号を圧縮することについて、質問で与えられた回避策の提案をカバーするべきです。エッジケースでは平均値が線形ではないため、入力信号を圧縮するだけでは完全な結果は得られませんが、エンドポイントは修正されます。
参考文献