เป็นวิธีที่เหมาะสมในการหนีบเสียงรบกวน dither คืออะไร?


9

เมื่อลดความลึกของสีและ dithering ด้วยเสียง 2 บิต (โดยมี n =] 0.5,1.5 [และเอาท์พุท = พื้น (อินพุต * (2 ^ บิต -1) + n)) จุดสิ้นสุดของช่วงค่า (อินพุต 0.0 และ 1.0 ) มีเสียงดัง มันจะเป็นที่พึงปรารถนาที่จะให้พวกเขาเป็นสีทึบ

ตัวอย่าง: https://www.shadertoy.com/view/llsfz4

เสียงรบกวน (ด้านบนเป็นสกรีนช็อตของ shadertoy ซึ่งเป็นภาพการไล่ระดับสีและปลายทั้งสองซึ่งควรเป็นสีขาวและดำตามลำดับ แต่มีเสียงดังแทน)

แน่นอนว่าปัญหาสามารถแก้ไขได้โดยเพียงแค่บีบอัดช่วงของค่าเพื่อให้จุดสิ้นสุดได้รับการปัดเศษเป็นค่าเดียวเสมอ แม้ว่าจะรู้สึกแฮ็คเล็กน้อยและฉันสงสัยว่าจะมีวิธีการใช้ "ถูกต้อง" นี้หรือไม่?


ด้วยเหตุผลบางอย่าง shadertoy ไม่ได้ทำงานบนเบราว์เซอร์ของฉัน คุณช่วยโพสต์ภาพง่าย ๆ เพื่อแสดงว่าคุณหมายถึงอะไร
Simon F

1
ไม่ควรจะเป็นเช่น n =] - 1, 1 [?
JarkkoL

@ JarkkoL สูตรการแปลงทศนิยมเป็นจำนวนเต็มคือ output = floor (อินพุต * intmax + n) โดยที่ = 0.5 โดยไม่มีเสียงรบกวนเพราะคุณต้องการ (ตัวอย่าง)> = 0.5 ถึงปัดขึ้น แต่ <0.5 ลง นั่นเป็นสาเหตุที่เสียง "อยู่กึ่งกลาง" ที่ 0.5
hotmultimedia

@SimonF เพิ่มรูปภาพของ shadertoy
hotmultimedia

1
ดูเหมือนว่าคุณกำลังตัดทอนผลลัพธ์แทนที่จะปัดเศษ (เช่น GPUs ทำ) - การปัดเศษแทนอย่างน้อยคุณก็จะได้ผ้าขาวที่เหมาะสม: shadertoy.com/view/MlsfD7 (ภาพ: i.stack.imgur.com/kxQWl.png )
Mikkel Gjoel

คำตอบ:


8

TL; DR: 2 * 1LSB รูปสามเหลี่ยมที่ pdf แตกหักในหน่วย edgecase ที่ 0 และ 1 เนื่องจากการหนีบ วิธีการแก้ปัญหาคือการ lerp เพื่อ 1 บิตสม่ำเสมอ dither ใน edgecases เหล่านั้น

ฉันกำลังเพิ่มคำตอบที่สองโดยเห็นว่านี่เป็นเรื่องที่ซับซ้อนกว่าที่ฉันคิดไว้เล็กน้อย ดูเหมือนว่าปัญหานี้เป็น "สิ่งที่ต้องทำ: จำเป็นต้องบีบหรือไม่" ในรหัสของฉันตั้งแต่ฉันเปลี่ยนจาก normalized เป็นรูปสามเหลี่ยม dithering ... ในปี 2012 รู้สึกดีที่ได้มองในที่สุด :) รหัสเต็มสำหรับการแก้ปัญหา / ภาพที่ใช้ตลอดการโพสต์: https://www.shadertoy.com/view/llXfzS

ก่อนอื่นนี่คือปัญหาที่เรากำลังดูเมื่อทำการหาปริมาณสัญญาณถึง 3 บิตด้วย 2 * 1LSB รูปสามเหลี่ยม pdf pdf:

เอาท์พุท - สิ่งที่ hotmultimedia แสดงให้เห็น

การเพิ่มความคมชัดผลที่อธิบายไว้ในคำถามชัดเจนขึ้น: ผลลัพธ์ไม่ได้เฉลี่ยกับสีดำ / ขาวใน edgecases (และจริง ๆ แล้วขยายเกิน 0/1 ก่อนที่จะทำเช่นนั้น)

ป้อนคำอธิบายรูปภาพที่นี่

การดูกราฟจะให้ข้อมูลเชิงลึกมากขึ้น:

ป้อนคำอธิบายรูปภาพที่นี่ (เส้นสีเทาทำเครื่องหมาย 0/1, สีเทายังเป็นสัญญาณที่เรากำลังพยายามเอาท์พุท, เส้นสีเหลืองคือค่าเฉลี่ยของเอาท์พุท dithered / quantized, สีแดงเป็นข้อผิดพลาด (สัญญาณเฉลี่ย))

ที่น่าสนใจไม่เพียง แต่ผลผลิตเฉลี่ยไม่ใช่ 0/1 ที่ขีด จำกัด แต่ก็ไม่เชิงเส้น เมื่อมองที่ปลายล่างมันทำให้เข้าใจได้ง่ายว่าทำไม diverges เอาท์พุท: เมื่อสัญญาณ dithered เริ่มรวมค่าลบ clamping-on-output จะเปลี่ยนค่าของส่วน dithered ด้านล่างของเอาต์พุต (เช่นค่าลบ) ดังนั้น การเพิ่มมูลค่าของค่าเฉลี่ย ภาพประกอบดูเหมือนจะอยู่ในลำดับ (ชุดรูปแบบสมมาตร 2LSB dither ค่าเฉลี่ยยังคงเป็นสีเหลือง):

ป้อนคำอธิบายรูปภาพที่นี่

ทีนี้ถ้าเราใช้ 1LSB normalized dither ไม่มีปัญหาในกรณีขอบเลย แต่แน่นอนว่าเราสูญเสียคุณสมบัติที่ดีของการทำสีสามเหลี่ยม (ดูตัวอย่างงานนำเสนอนี้ )

ป้อนคำอธิบายรูปภาพที่นี่

วิธีแก้ปัญหา (ในทางปฏิบัติเชิงประจักษ์) (แฮ็ค) คือเปลี่ยนกลับเป็น [-0.5; 0.5 [การทำให้เหมือนกันอย่างสิ้นเชิงสำหรับ edgecase:

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

ซึ่งแก้ไข edgecases ในขณะที่รักษารูปสามเหลี่ยมที่ยังคงสภาพเหมือนเดิมไว้สำหรับช่วงที่เหลืออยู่:

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นเพื่อที่จะไม่ตอบคำถามของคุณ: ฉันไม่รู้ว่ามีวิธีแก้ปัญหาทางคณิตศาสตร์ที่ดีกว่านี้หรือไม่และกระตือรือร้นที่จะรู้ว่า Masters of Past ได้ทำอะไรไปบ้าง :) อย่างน้อยเราก็มีแฮ็คที่น่ากลัวนี้

แก้ไข
ฉันควรจะครอบคลุมข้อเสนอแนะการแก้ปัญหาที่กำหนดในคำถามเพียงแค่บีบอัดสัญญาณ เนื่องจากค่าเฉลี่ยไม่เชิงเส้นใน edgecases เพียงการบีบอัดสัญญาณอินพุตจึงไม่ให้ผลลัพธ์ที่สมบูรณ์แบบ - แม้ว่าจะแก้ไขจุดสิ้นสุด: ป้อนคำอธิบายรูปภาพที่นี่

อ้างอิง


มันวิเศษมากที่การเยื้องขอบที่ให้ผลลัพธ์ที่สมบูรณ์แบบ ฉันคาดหวังอย่างน้อยการเบี่ยงเบน: P
Alan Wolfe

ใช่ฉันรู้สึกประหลาดใจในเชิงบวกด้วยเช่นกัน :) ฉันเชื่อว่ามันใช้งานได้เพราะเราลดขนาดลงสองเท่าเป็นเส้นตรงในอัตราเดียวกันสัญญาณจะลดลง ดังนั้นอย่างน้อยขนาดก็ตรงกัน ... แต่ฉันยอมรับว่ามันน่าสนใจที่การผสมการกระจายโดยตรงดูเหมือนจะไม่มีผลข้างเคียงที่เป็นลบ
Mikkel Gjoel

@MikkelGjoel แต่น่าเสียดายที่ความเชื่อของคุณไม่ถูกต้องเนื่องจากข้อผิดพลาดในรหัสของคุณ คุณใช้ RNG เดียวกันซ้ำสำหรับทั้งสองdithertriและdithernormแทนที่จะใช้ RNG อิสระ เมื่อคุณทำงานกับคณิตศาสตร์ทั้งหมดและยกเลิกข้อกำหนดทั้งหมดคุณจะพบว่าคุณไม่ได้อ่านทั้งหมด! แต่รหัสจะทำหน้าที่เหมือนการตัดอย่างหนักที่v < 0.5 / depth || v > 1 - 0.5/depthทันทีเปลี่ยนเป็นการกระจายแบบเดียวกันที่นั่น ไม่ใช่ว่ามันจะนำคุณออกไปจากสิ่งที่สวยงามที่คุณมีมันซับซ้อนอย่างไร้ความจำเป็น การแก้ไขข้อผิดพลาดนั้นไม่ดีจริง ๆ คุณจะต้องพบกับข้อบกพร่องที่แย่ลง เพียงใช้จุดตัดอย่างแรง
orlp

หลังจากขุดให้ลึกลงไปฉันพบปัญหาอีกประการหนึ่งใน shadertoy ที่คุณไม่ทำการแก้ไขแกมม่าในขณะที่หาค่าเฉลี่ยตัวอย่าง (คุณเฉลี่ยในพื้นที่ sRGB ซึ่งไม่ใช่เชิงเส้น) หากคุณจัดการกับแกมม่าอย่างเหมาะสมเราพบว่าน่าเสียดายที่เรายังไม่ได้ทำ เราต้องกำหนดเสียงของเราเพื่อจัดการกับการแก้ไขแกมม่า นี่คือการแสดง shadertoy ปัญหา: shadertoy.com/view/3tf3Dn ฉันได้พยายามพวงของสิ่งและไม่สามารถได้รับมันในการทำงานเพื่อให้ผมโพสต์คำถามที่นี่: computergraphics.stackexchange.com/questions/8793/...
orlp

3

ฉันไม่แน่ใจว่าฉันสามารถตอบคำถามของคุณได้อย่างเต็มที่ แต่ฉันจะเพิ่มความคิดและบางทีเราอาจจะได้คำตอบด้วยกัน :)

ขั้นแรกรากฐานของคำถามนั้นไม่ค่อยชัดเจนสำหรับฉัน: ทำไมคุณถึงคิดว่าเป็นที่พึงปรารถนาที่จะมีสีดำ / ขาวสะอาดเมื่อสีอื่น ๆ ทุกครั้งมีเสียงดัง? ผลลัพธ์ที่ดีที่สุดหลังจากการทำ dithering คือสัญญาณดั้งเดิมของคุณพร้อมสัญญาณรบกวนที่สม่ำเสมอ หากขาวดำแตกต่างกันเสียงของคุณจะขึ้นอยู่กับสัญญาณ (ซึ่งอาจไม่เป็นไรเพราะมันเกิดขึ้นเมื่อมีการยึดสี)

ที่กล่าวว่ามีสถานการณ์ที่มีสัญญาณรบกวนในสีขาวหรือดำจะก่อปัญหา (ฉันไม่ทราบ usecases ที่ต้องการทั้งขาวดำและพร้อมที่จะ "สะอาด"): เมื่อเรนเดอร์ผสมอนุภาคเป็นรูปสี่เหลี่ยมด้วย พื้นผิวคุณไม่ต้องการเสียงรบกวนที่เพิ่มขึ้นในรูปสี่เหลี่ยมทั้งหมดซึ่งจะแสดงนอกพื้นผิวด้วย ทางออกหนึ่งคือการชดเชยสัญญาณรบกวนดังนั้นแทนที่จะเพิ่ม [-0.5; 1.5 [คุณเพิ่ม [-2.0; 0.0 [(เช่นลบเสียง 2 บิต) นี่เป็นวิธีเชิงประจักษ์ แต่ฉันไม่รู้วิธีที่ถูกต้องมากกว่านี้ เมื่อพิจารณาถึงเรื่องนี้คุณอาจต้องการเพิ่มสัญญาณของคุณเพื่อชดเชยความเข้มที่หายไป ...

ค่อนข้างเกี่ยวข้องกับทิโมธี Lottes ได้พูดคุย GDC เกี่ยวกับการสร้างเสียงไปยังส่วนของสเปกตรัมที่มีความจำเป็นมากที่สุดลดเสียงรบกวนในปลายสดใสของสเปกตรัม: http://32ipi028l5q82yhj72224m8j-wpengine.netdna-ssl.com/wp- content / uploads / 2016/03 / GdcVdrLottes.pdf


(ขออภัยที่ฉันกด Enter โดยไม่ได้ตั้งใจและเวลาที่ จำกัด การแก้ไขหมดอายุ) usecase ในตัวอย่างเป็นหนึ่งในสถานการณ์เหล่านั้นที่มันจะมีความสำคัญ: การแสดงผลจุดลอยสีเทาภาพบนอุปกรณ์แสดงผล 3 บิต นี่คือความเข้มที่เปลี่ยนแปลงอย่างมากเพียงแค่เปลี่ยน LSB ฉันพยายามที่จะเข้าใจว่ามี "วิธีที่ถูกต้อง" ใด ๆ ที่จะมีการแมปค่าสิ้นสุดไปยังสีทึบเช่นการบีบอัดช่วงค่าและมีค่าสิ้นสุดอิ่มตัว และคำอธิบายทางคณิตศาสตร์ของสิ่งนั้นคืออะไร? ในสูตรตัวอย่างค่าอินพุตที่ 1.0 ไม่ได้สร้างผลลัพธ์ที่ค่าเฉลี่ยถึง 7 และนั่นคือสิ่งที่รบกวนฉัน
hotmultimedia

1

ฉันทำให้ความคิดของ Mikkel Gjoel ง่ายขึ้นโดยการลดทอนสัญญาณรบกวนแบบสามเหลี่ยมเป็นฟังก์ชั่นง่าย ๆ ที่ต้องใช้การเรียก RNG เพียงครั้งเดียว ฉันได้ถอดบิตที่ไม่จำเป็นออกไปดังนั้นมันควรจะอ่านง่ายและเข้าใจได้ว่าเกิดอะไรขึ้น:

// 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.