Renk taklidi gürültüsünü sıkıştırmanın uygun bir yolu nedir?


9

Renk derinliğini azaltırken ve 2 bit parazitle (n =] 0,5,1,5 [ve çıktı = kat (giriş * (2 ^ bit-1) + n) ile) titreme yaparken, değer aralığının uçları (0,0 ve 1,0 girişleri) ) gürültülü. Düz renk olmaları arzu edilir.

Örnek: https://www.shadertoy.com/view/llsfz4

Gürültü gradyanı (yukarıdaki shadertoy'un ekran görüntüsüdür, bir gradyanı ve her iki ucu da sırasıyla düz beyaz ve siyah olmalıdır , ancak bunun yerine gürültülüdür)

Sorun elbette sadece değer aralığını sıkıştırarak çözülebilir, böylece uçlar her zaman tek değerlere yuvarlanır. Bu biraz hack geliyor ve bunu "düzgün" uygulamak için bir yol olup olmadığını merak ediyorum?


Nedense shadertoy tarayıcımda çalışmadı. Ne demek istediğinizi göstermek için basit resimler yayınlayabilir misiniz?
Simon F

1
Daha çok n =] - 1, 1 [?
JarkkoL

@JarkkoL Kayan noktayı tamsayıya dönüştürmek için formül çıktı = zemin (giriş * intmax + n), burada n = 0,5 gürültüsüz, çünkü (örneğin) = 0,5 yuvarlamak, ancak <0,5 aşağı. Bu yüzden gürültü 0,5'te "merkezlenir".
hotmultimedia

@SimonF, shadertoy görüntüsünü ekledi
hotmultimedia

1
Çıkışı yuvarlamak yerine kesiyorsunuz ( GPU'lar gibi) - bunun yerine yuvarlama, en azından uygun beyazları elde edersiniz: shadertoy.com/view/MlsfD7 (image: i.stack.imgur.com/kxQWl.png )
Mikkel Gjoel

Yanıtlar:


8

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:

çıktılar - 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).

resim açıklamasını buraya girin

Bir grafiğe bakmak biraz daha fazla bilgi sağlar:

resim açıklamasını buraya girin (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):

resim açıklamasını buraya girin

Ş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 ).

resim açıklamasını buraya girin

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:

resim açıklamasını buraya girin

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: resim açıklamasını buraya girin

Referanslar


Kenarlardaki lerp'in mükemmel görünümlü bir sonuç vermesi şaşırtıcı. En azından biraz sapma beklerdim: P
Alan Wolfe

Evet, ben de çok şaşırdım :) İşe yarayacağımıza inanıyorum çünkü renk taklidi büyüklüğünü doğrusal olarak küçültüyoruz, aynı oranda sinyal azalıyor. O zaman en azından ölçek eşleşiyor ... ama dağıtımları doğrudan karıştırmanın olumsuz bir yan etkisi olmadığı ilginç.
Mikkel Gjoel

@MikkelGjoel Maalesef, kodunuzdaki bir hata nedeniyle inancınız yanlış. Aynı RNG'yi her ikisi için dithertrive dithernormbağımsız yerine yeniden kullandınız . Bir kez tüm matematik üzerinde çalışmak ve tüm terimleri iptal ettikten sonra, hiç hareket etmediğini bulacaksınız! Bunun yerine, kod v < 0.5 / depth || v > 1 - 0.5/depthanında orada tekdüze dağılıma geçerek sert bir kesme görevi görür . Sahip olduğunuz güzel renk taklidinden uzaklaştığı için değil, sadece gereksiz derecede karmaşık. Hatayı düzeltmek gerçekten kötü, daha kötü bir renk taklidi ile sonuçlanacaksınız. Sadece sert bir kesme kullanın.
orlp

Daha derine intikten sonra, shadertoy'nuzda örneklerin ortalamasını alırken gama düzeltmesi yapmadığınız başka bir sorun buldum (doğrusal olmayan sRGB alanında ortalama). Gamaya uygun şekilde bakarsanız maalesef henüz bitmediğimizi görüyoruz. Gama düzeltmesi ile başa çıkmak için sesimizi şekillendirmeliyiz. Sorunu gösteren bir gölgelendirici: shadertoy.com/view/3tf3Dn . Bir sürü şey denedim ve işe yaramadı, bu yüzden burada bir soru gönderdim: computergraphics.stackexchange.com/questions/8793/… .
orlp

3

Sorunuza tam olarak cevap verebileceğimden emin değilim, ancak bazı düşünceler ekleyeceğim ve belki birlikte bir cevaba ulaşabiliriz :)

Birincisi, sorunun temeli benim için biraz belirsiz: Neden diğer her renkte gürültü olduğunda temiz siyah / beyaz olması isteniyor? Titreme sonrası ideal sonuç, tamamen eşit gürültüye sahip orijinal sinyalinizdir. Siyah ve beyaz farklıysa, gürültünüz sinyale bağımlı hale gelir (yine de renklerin zaten kenetlendiği yerlerde olduğu için iyi olabilir).

Bununla birlikte, beyazlarda veya siyahlarda gürültüye sahip olmanın bir sorun oluşturduğu durumlar vardır (siyah ve beyazın aynı anda "temiz" olmasını gerektiren kullanımların farkında değilim): Katkı maddesi ile karıştırılmış bir parçacığı dörtlü olarak oluştururken bir doku, tüm dörtlüde gürültü eklenmesini istemezsiniz, çünkü bu doku dışında da gösterilir. Bir çözüm gürültüyü dengelemektir, bu yüzden [-0.5; 1.5 [eklemek [-2.0; 0.0 [eklersiniz (yani 2 bit gürültü çıkarırsınız). Bu oldukça ampirik bir çözüm, ancak daha doğru bir yaklaşımın farkında değilim. Bunu düşünerek, muhtemelen kayıp yoğunluğu telafi etmek için sinyalinizi artırmak istersiniz ...

Biraz ilgili olan Timothy Lottes, spektrumun en çok ihtiyaç duyulduğu yerlere gürültü şekillendirme ve spektrumun parlak ucundaki gürültüyü azaltma konusunda bir GDC konuşması yaptı: http://32ipi028l5q82yhj72224m8j-wpengine.netdna-ssl.com/wp- content / uploads / 2016/03 / GdcVdrLottes.pdf


(üzgünüm yanlışlıkla enter tuşuna bastım ve zaman sınırını düzenleme sona erdi) Örnekteki usecase, önemli olan durumlardan biridir: 3 bitlik bir görüntüleme cihazında kayan nokta gri tonlamalı bir görüntü oluşturma. Burada yoğunluk sadece LSB'yi değiştirerek büyük ölçüde değişir. Ben değer aralığını sıkıştırmak ve bitiş değerleri doygunluk var gibi katı renk eşleme için son değerleri var herhangi bir "doğru yolu" olup olmadığını anlamaya çalışıyorum. Ve bunun matematiksel açıklaması nedir? Örnek formülde, 1.0 giriş değeri ortalama 7 olan çıktı üretmez ve bu beni rahatsız eder.
hotmultimedia

1

Mikkel Gjoel'in sadece tek bir RNG çağrısına ihtiyaç duyan basit bir işleve üçgen gürültü ile titreme fikrini basitleştirdim. Gereksiz tüm bitleri çıkardım, bu yüzden neler olduğunu oldukça okunabilir ve anlaşılır olmalı:

// 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));
}

Fikir ve bağlam için sizi Mikkel Gjoel'in cevabına yönlendireceğim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.