Một cách thích hợp để kẹp tiếng ồn là gì?


9

Khi giảm độ sâu màu và phối màu với nhiễu 2 bit (với n =] 0,5,1,5 [và đầu ra = sàn (đầu vào * (2 ^ bit-1) + n)), các đầu của dải giá trị (đầu vào 0,0 và 1,0 ) đang ồn ào. Nó sẽ được mong muốn để có được màu rắn.

Ví dụ: https://www.shadertoy.com/view/llsfz4

Độ dốc tiếng ồn (ở trên là ảnh chụp màn hình của shadertoy, hình dung một gradient và cả hai đầu nên có màu trắng và đen tương ứng, nhưng thay vào đó là nhiễu)

Tất nhiên, vấn đề có thể được giải quyết bằng cách chỉ nén phạm vi giá trị để các đầu luôn luôn được làm tròn thành các giá trị đơn. Điều này cảm thấy một chút hack, và tôi tự hỏi liệu có cách nào để thực hiện "đúng" này không?


Vì một số lý do, shadertoy không chạy trên trình duyệt của tôi. Bạn có thể đăng một / một số hình ảnh đơn giản để chứng minh ý của bạn không?
Simon F

1
Không nên giống như n =] - 1, 1 [?
JarkkoL

@JarkkoL Vâng, công thức để chuyển đổi dấu phẩy động thành số nguyên là output = floor (đầu vào * intmax + n), trong đó n = 0,5 không có nhiễu, vì bạn muốn (ví dụ)> = 0,5 để làm tròn, nhưng <0,5 xuống. Đó là lý do tại sao tiếng ồn được "tập trung" ở mức 0,5.
hotmultidia

@SimonF đã thêm hình ảnh của shadertoy
hotmultidia

1
Có vẻ như bạn đã cắt bớt đầu ra thay vì làm tròn nó (như GPU làm) - thay vào đó, làm tròn, ít nhất bạn sẽ có được những người da trắng thích hợp: shadertoy.com/view/MlsfD7 (hình ảnh: i.stack.imgur.com/kxQWl.png )
Mikkel Gjoel

Câu trả lời:


8

TL; DR: phối màu 2 * 1LSB phá vỡ hình tam giác-pdf trong edgecase ở 0 và 1 do kẹp. Một giải pháp là lerp để hòa sắc 1bit trong các edgecase đó.

Tôi đang thêm một câu trả lời thứ hai, vì điều này hóa ra hơi phức tạp hơn tôi nghĩ ban đầu. Có vẻ như vấn đề này đã là "TODO: cần kẹp?" trong mã của tôi kể từ khi tôi chuyển từ chuẩn hóa sang phối màu tam giác ... vào năm 2012. Cảm thấy tốt khi cuối cùng nhìn vào nó :) Mã đầy đủ cho giải pháp / hình ảnh được sử dụng trong suốt bài đăng: https://www.shadertoy.com/view/llXfzS

Trước hết, đây là vấn đề chúng tôi đang xem xét, khi định lượng tín hiệu thành 3 bit với phối màu tam giác 2 * 1LSB:

đầu ra - về cơ bản những gì hotmultidia đã cho thấy.

Tăng độ tương phản, hiệu ứng được mô tả trong câu hỏi trở nên rõ ràng: Đầu ra không trung bình thành đen / trắng trong các edgecase (và thực sự kéo dài quá 0/1 trước khi thực hiện).

nhập mô tả hình ảnh ở đây

Nhìn vào biểu đồ cung cấp một cái nhìn sâu sắc hơn một chút:

nhập mô tả hình ảnh ở đây (vạch màu xám đánh dấu 0/1, còn màu xám là tín hiệu chúng ta đang cố gắng phát ra, đường màu vàng là trung bình của đầu ra được phối màu / lượng tử hóa, màu đỏ là lỗi (trung bình tín hiệu)).

Thật thú vị, không chỉ là đầu ra trung bình không 0/1 ở các giới hạn, nó cũng không phải là tuyến tính (có thể là do pdf tam giác của tiếng ồn). Nhìn ở đầu dưới, nó có ý nghĩa trực quan tại sao đầu ra phân kỳ: Khi tín hiệu hòa sắc bắt đầu bao gồm các giá trị âm, đầu ra kẹp thay đổi giá trị của các phần được phối màu thấp hơn của đầu ra (nghĩa là các giá trị âm), do đó tăng giá trị trung bình. Một hình minh họa dường như theo thứ tự (hoà sắc, hòa sắc 2LSB đối xứng, trung bình vẫn có màu vàng):

nhập mô tả hình ảnh ở đây

Bây giờ, nếu chúng ta chỉ sử dụng một hoà sắc chuẩn hóa 1LSB, thì không có vấn đề gì ở các trường hợp cạnh, nhưng tất nhiên chúng ta sẽ mất các tính chất đẹp của phối màu tam giác (xem ví dụ: bản trình bày này ).

nhập mô tả hình ảnh ở đây

Sau đó, một giải pháp (thực dụng, theo kinh nghiệm) (hack) là hoàn nguyên về [-0,5; 0,5 [phối màu đồng nhất cho 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) );

Cái nào sửa các edgecase trong khi vẫn giữ nguyên độ hoà sắc tam giác cho phạm vi còn lại:

nhập mô tả hình ảnh ở đây

Vì vậy, để không trả lời câu hỏi của bạn: Tôi không biết liệu có một giải pháp vững chắc hơn về mặt toán học hay không, và cũng rất muốn biết Masters of Past đã làm gì :) Cho đến lúc đó, ít nhất chúng ta có bản hack khủng khiếp này để giữ cho mã của chúng ta hoạt động.

EDIT
Có lẽ tôi nên đề xuất cách giải quyết được đưa ra trong Câu hỏi, chỉ đơn giản là nén tín hiệu. Bởi vì trung bình không phải là tuyến tính trong các edgecase, chỉ cần nén tín hiệu đầu vào không tạo ra kết quả hoàn hảo - mặc dù nó đã sửa các điểm cuối: nhập mô tả hình ảnh ở đây

Người giới thiệu


Thật đáng kinh ngạc khi lerp ở các cạnh cho kết quả hoàn hảo. Tôi sẽ mong đợi ít nhất một chút sai lệch: P
Alan Wolfe

Phải, tôi cũng rất ngạc nhiên :) Tôi tin rằng nó hoạt động bởi vì chúng tôi đang giảm quy mô tuyến tính, với cùng tốc độ tín hiệu đang giảm. Vì vậy, ít nhất là tỷ lệ khớp với ... nhưng tôi đồng ý rằng thật thú vị khi trộn trực tiếp các bản phân phối dường như không có tác dụng phụ tiêu cực.
Mikkel Gjoel

@MikkelGjoel Thật không may, niềm tin của bạn không chính xác do lỗi trong mã của bạn. Bạn đã sử dụng lại cùng một RNG cho cả hai dithertridithernormthay vì một RNG độc lập. Khi bạn hoàn thành tất cả các phép toán và hủy bỏ tất cả các điều khoản, bạn sẽ thấy rằng bạn không hề nản chí chút nào! Thay vào đó, mã hoạt động giống như một điểm cắt cứng tại v < 0.5 / depth || v > 1 - 0.5/depth, ngay lập tức chuyển sang phân phối thống nhất ở đó. Không phải là nó mất đi sự phối màu tốt đẹp mà bạn có, nó chỉ là phức tạp không cần thiết. Sửa lỗi thực sự là xấu, bạn sẽ kết thúc với một hoà sắc tồi tệ hơn. Chỉ cần sử dụng một cutoff cứng.
orlp

Sau khi đào sâu hơn nữa, tôi đã tìm thấy một vấn đề khác trong shadertoy của bạn, nơi bạn không thực hiện sửa lỗi gamma trong khi lấy trung bình các mẫu (bạn trung bình trong không gian sRGB không phải là tuyến tính). Nếu bạn xử lý gamma một cách thích hợp, chúng tôi thấy rằng thật không may, chúng tôi chưa hoàn thành. Chúng ta phải định hình tiếng ồn của mình để đối phó với sự điều chỉnh gamma. Dưới đây là một shadertoy hiển thị vấn đề: shadertoy.com/view/3tf3Dn . Tôi đã thử rất nhiều thứ và không thể làm cho nó hoạt động được, vì vậy tôi đã đăng một câu hỏi ở đây: computergraphics.stackexchange.com/questions/8793/ Lỗi .
orlp

3

Tôi không chắc chắn tôi có thể trả lời đầy đủ câu hỏi của bạn, nhưng tôi sẽ thêm một số suy nghĩ và có lẽ chúng ta có thể đi đến một câu trả lời cùng nhau :)

Đầu tiên, nền tảng của câu hỏi là một chút không rõ ràng đối với tôi: Tại sao bạn cho rằng nó có màu đen / trắng sạch khi mọi màu khác có tiếng ồn? Kết quả lý tưởng sau khi phối màu là tín hiệu ban đầu của bạn với nhiễu hoàn toàn đồng nhất. Nếu đen và trắng khác nhau, nhiễu của bạn trở nên phụ thuộc vào tín hiệu (mặc dù điều này có thể ổn, vì dù sao thì màu cũng được kẹp lại).

Điều đó nói rằng, có những tình huống, trong đó có tiếng ồn ở cả người da trắng hoặc người da đen đều gây ra vấn đề (tôi không biết các giai đoạn yêu cầu cả hai màu đen và trắng phải "sạch"): Khi kết xuất một hạt được trộn lẫn với nhau như một hình tứ giác với một kết cấu, bạn không muốn thêm nhiễu trong toàn bộ tứ giác, vì điều đó cũng sẽ hiển thị bên ngoài kết cấu. Một giải pháp là bù nhiễu, thay vì thêm [-0,5; 1,5 [bạn thêm [-2.0; 0.0 [(tức là trừ 2 bit tiếng ồn). Đây là một giải pháp thực nghiệm, nhưng tôi không biết cách tiếp cận đúng hơn. Nghĩ về nó, có khả năng bạn cũng muốn tăng tín hiệu của mình để bù cho cường độ đã mất ...

Một phần nào đó có liên quan, Timothy Lottes đã nói về GDC về việc định hình nhiễu cho các phần của phổ nơi cần thiết nhất, giảm nhiễu ở phần cuối của phổ: http://32ipi028l5q82yhj72224m8j-wpengine.netdna-ssl.com/w- nội dung / tải lên / 2016/03 / GdcVdrLottes.pdf


(xin lỗi, tôi vô tình nhấn enter và chỉnh sửa giới hạn thời gian đã hết hạn) Ví dụ trong ví dụ này là một trong những tình huống quan trọng: hiển thị hình ảnh thang độ xám nổi trên thiết bị hiển thị 3 bit. Ở đây cường độ thay đổi lớn chỉ bằng cách thay đổi LSB. Tôi đang cố gắng hiểu liệu có "cách chính xác" nào để ánh xạ giá trị kết thúc thành màu đơn sắc, như nén phạm vi giá trị và có giá trị cuối bão hòa không. Và giải thích toán học về điều đó là gì? Trong công thức ví dụ, giá trị đầu vào của 1.0 không tạo ra đầu ra trung bình bằng 7 và đó là điều làm tôi khó chịu.
hotmultidia

1

Tôi đã đơn giản hóa ý tưởng phối màu của Mikkel Gjoel với nhiễu hình tam giác thành một chức năng đơn giản chỉ cần một cuộc gọi RNG duy nhất. Tôi đã loại bỏ tất cả các bit không cần thiết để nó có thể dễ đọc và dễ hiểu những gì đang diễn ra:

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

Đối với ý tưởng và bối cảnh tôi sẽ giới thiệu bạn đến câu trả lời của Mikkel Gjoel.


0

Tôi đã theo các liên kết đến câu hỏi tuyệt vời này cùng với ví dụ về shadertoy.

Tôi có một vài câu hỏi về giải pháp được đề xuất:

  1. Giá trị v là gì? Có phải đó là tín hiệu RGB trong phạm vi 0,0 đến 1,0 (đen sang trắng) mà chúng ta muốn định lượng? Có phải là một phao đơn? (và nếu vậy, bạn đã tính toán nó như thế nào từ tín hiệu RGB gốc?)
  2. Nguồn gốc của số ma thuật của người Hồi giáo 0,5 / 7,0 là gì? Tôi giả sử đó là một nửa thùng, nhưng tôi hy vọng rằng kích thước của thùng được biểu thị bằng 8 bit là 1.0 / 255.0, vì vậy tôi rất ngạc nhiên khi thấy 0,5 / 0,7. Bạn có phiền giải thích làm thế nào bạn bắt nguồn những con số này. Tôi đang thiếu gì?
  3. Tôi giả sử phân phối tam giác nằm trong phạm vi [-1,1] và đồng phục nằm trong [-0,5,0,5] (Nửa bit bit vì chúng tôi ở gần rìa và chúng tôi không muốn vượt quá - đó là logic bạn áp dụng?)
  4. Các biến ngẫu nhiên đồng nhất và tam giác nên độc lập. Tôi có đúng không?

Công việc tuyệt vời Tôi muốn thấy rằng tôi hiểu chính xác dòng suy nghĩ của bạn. Cảm ơn!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.