TL; DR: 2 * 1LSB üçgen-pdf titreme, kenetlenme nedeniyle 0 ve 1'de edgekazlarda kırılır. Bir çözüm, bu edgekazlarda 1 bitlik tek renk taklidine geçmektir.
İkinci bir cevap ekliyorum, çünkü bu aslında düşündüğümden biraz daha karmaşık çıktı. Görünüşe göre bu sorun bir "TODO: kelepçeleme mi gerekiyor?" normalde üçgen renk taklidine geçtiğimden beri kodumda ... 2012'de. Sonunda bakmak iyi hissettiriyor :) Yazı boyunca kullanılan çözüm / resimler için tam kod: https://www.shadertoy.com/view/llXfzS
Her şeyden önce, bir sinyali 2 * 1LSB üçgen-pdf renk taklidi ile 3 bit olarak ölçerken baktığımız sorun:
- esasen hotmultimedia'nın gösterdiği şey.
Artan kontrast, soruda açıklanan etki belirgin hale gelir: Çıktı, edgekazlarda siyah / beyaz ile ortalama değildir (ve bunu yapmadan önce 0 / 1'in çok ötesine uzanır).
Bir grafiğe bakmak biraz daha fazla bilgi sağlar:
(gri çizgiler 0 / 1'i işaretler, gri de çıktı almaya çalıştığımız sinyaldir, sarı çizgi deitmi alınmış / nicelleştirilmiş çıktı ortalamasıdır, kırmızı hatadır (sinyal ortalaması)).
İlginçtir, sadece ortalama çıktı sınırlarda 0/1 değil, aynı zamanda doğrusal da değildir (muhtemelen gürültünün üçgen pdf'sinden dolayı). Alt uca bakıldığında, çıktının neden farklılaştığı sezgisel bir anlam ifade eder: Titreşen sinyal negatif değerler içermeye başladığında, çıkışa kenetleme, çıktının alt titrek parçalarının (yani negatif değerlerin) değerini değiştirir, böylece ortalamanın değerini artırmak. Bir resim sıralı gibi görünüyor (düzgün, simetrik 2LSB renk taklidi, ortalama hala sarı renkte):
Şimdi, sadece 1LSB normalleştirilmiş renk taklidi kullanırsak, kenar durumlarda hiç sorun olmaz, ancak elbette üçgen renk taklidinin güzel özelliklerini kaybederiz (örneğin bu sunuma bakınız ).
O zaman (pragmatik, ampirik) bir çözüm (hack), edgekaz için [-0.5; 0.5 [eşit renk taklidi] 'ne dönmektir:
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) );
Üçgen renk taklidini kalan aralık için korurken edgecas'ları sabitler:
Sorunuzu cevaplamamak için: Daha matematiksel olarak daha sağlam bir çözüm olup olmadığını bilmiyorum ve Geçmişin Üstatlarının ne yaptığını bilmek için aynı derecede istekliyim :) O zamana kadar, en azından kodumuzu işlemek için bu korkunç kesmek var.
EDIT
Muhtemelen, sadece sinyali sıkıştırmayla ilgili Soru'da verilen geçici çözümü önermelidir. Kenar boşluklarında ortalama doğrusal olmadığından, giriş sinyalini sıkıştırmak mükemmel bir sonuç vermez - ancak uç noktaları sabitler:
Referanslar