Correct SRGB Dithering

栏目: IT技术 · 发布时间: 4年前

内容简介:This is a brain-dump inspired by a thread on twit­ter about cor­rect™ dither inSo, this top­ic came up on twit­ter:I had pre­vi­ous­ly spent some time to wrap my head around this exact prob­lem, so I shot from the hip with some pseu­do code that I used in

This is a brain-dump inspired by a thread on twit­ter about cor­rect™ dither in sRGB , mean­ing, to choose the dither pat­tern in such a way as to pre­serve the phys­i­cal bright­ness of the orig­i­nal pix­els. This is in prin­ci­ple a solved prob­lem, but the dev­il is in the details that are eas­i­ly over­looked, espe­cial­ly when dither­ing to only a few quan­ti­za­tion lev­els.

So, this top­ic came up on twit­ter:

Correct SRGB Dithering

I had pre­vi­ous­ly spent some time to wrap my head around this exact prob­lem, so I shot from the hip with some pseu­do code that I used in Space Glid­er on Shader­toy. Code post­ings on twit­ter are nev­er a good idea, so here is a cleaned up ver­sion wrapped up in a prop­er func­tion:

vec3 oetf( vec3 );    // = pow( .4545 )
vec3 eotf( vec3 );    // = pow( 2.2 )
 
vec3 dither( vec3 linear_color, vec3 noise, float quant )
{
    vec3 c0 = floor( oetf( linear_color ) / quant ) * quant;
    vec3 c1 = c0 + quant;
    vec3 discr = mix( eotf( c0 ), eotf( c1 ), noise );
    return mix( c0, c1, lessThan( discr, linear_color ) );
}

Con­tents

How the code works

The linear_color is the val­ue that is going to be writ­ten out to the ren­der tar­get. This is the val­ue to be dithered and is sup­posed to be in lin­ear RGB . The noise argu­ment can be any uni­form noise in the range 0 to 1 (prefer­ably some form of blue noise, or it could be an ordered Bay­er-pat­tern). Last­ly, the quant argu­ment is the quan­ti­za­tion inter­val, which is “one over one minus the num­ber of lev­els”; for exam­ple: 1/255 for quan­ti­za­tion to 256 lev­els, or 51/255 so emu­late the palette of web-safe col­ors (6 lev­els). The free func­tion oetf is used here to stand for an arbi­trary opto-elec­tron­ic trans­fer func­tion , which for sRGB is noth­ing more than the good old gam­ma curve.

Here is how the dither func­tion works: It first com­putes the quan­tized low­er and upper bounds, c0 and c1 , that brack­et the input val­ue. The out­put is then select­ed as either c0 or c1 based on a com­par­i­son of the input against a dis­crim­i­nant, discr . The salient point is that this com­par­i­son is per­formed in lin­ear space!

Correct SRGB Dithering

So why is it nec­es­sary to com­pute the dis­crim­i­nant in lin­ear space? Because what mat­ters is phys­i­cal bright­ness, which is lin­ear in the num­ber of pix­els (at least it should be, on a sane dis­play), but it is not in gen­er­al lin­ear in the RGB val­ue ifself.

Why the code works

To illus­trate fur­ther lets con­tin­ue with the web palette exam­ple where there are 6 quan­ti­za­tion lev­els. The fol­low­ing table shows how these 6 lev­els should map to phys­i­cal lumi­nance, accord­ing to the sRGB-stan­dard:

val­ue

PERCENT

)

val­ue

(8 bit)

Val­ue

HEX

)

lumi­nance

(cD per sq meter)

exam­ple
0% 0 #00 0
20% 51 #33 3,31
40% 102 #66 13,3
60% 153 #99 31,9
80% 204 # CC 60,4
100% 255 # FF 80

The lumi­nance val­ues here were cal­cu­lat­ed by fol­low­ing the sRGB trans­fer func­tion and under the assump­tion of the stan­dard 80 cd/m² dis­play bright­ness. Now con­sid­er for exam­ple that we want to match the lumi­nance of the #33 grey val­ue (3,31 cd/m²) with a dither pat­tern. Accord­ing to table we should choose a 25% pat­tern when using the #66 pix­els (3,31 into 13,3), a 10% pat­tern for the #99 pix­els (3,31 into 31,9), a 5,4% pat­tern for the # CC pix­els (3,31 into 60,4) or a 4,1% pat­tern for the # FF pix­els (3,31 into 80). This has been real­ized in the fol­low­ing image:

All tiles in this image should appear approx­i­mate­ly with the same bright­ness. They may not match per­fect­ly on your dis­play, but they should do at least ok. Make sure the image is viewed at its orig­i­nal size. To min­i­mize resiz­ing errors I have includ­ed a 2× ver­sion for reti­na dis­plays that should get auto­mat­i­cal­ly select­ed on Mac­Books and the like.

In con­trast, using the raw RGB val­ue as the basis for the dither pat­tern as shown above does not pro­duce a match­ing appear­ance. In this case I used a 50% pat­tern with the #66 pix­els (20 into 40), a 33% pat­tern with #99 pix­els (20 into 60), a 25% pat­tern with # CC pix­els (20 into 80) and a 20% pat­tern with # FF pix­els (20 into 100). See for your­self how that does not match!

A real world example

As I said in the begin­ning, I came up with the above dither­ing code as a side effect of the con­tin­ued tin­ker­ing with Space Glid­er, as I want­ed to have a some­what faith­ful ren­di­tion of twi­light and night sit­u­a­tions, and that means that with­out dither­ing, the sky gra­di­ent would pro­duce very not­i­ca­ble band­ing, espe­cial­ly so in VR .

To illius­trate, a took a screen­shot of a twi­light scene, stand­ing in the moun­tains with the land­ing lights on. The dark­est pix­el in this image is #020204, which is some­where in the low­er left cor­ner. With a VR head­set on, and with the eyes dark-adapt­ed, the jumps between #02, #03 and #04 are clear­ly vis­i­ble and prop­er dither­ing is a must.

I will now show how the code shown in the begin­ning is work­ing as intend­ed by dither­ing this image to 2, 3, 4, 6 and 8 quan­ti­za­tion lev­els by sim­ply chanch­ing the quant vari­able. Again, all images should match phys­i­cal bright­ness impres­sion (and again, on the con­di­tion that your brows­er does not mess with the pix­els). The noise input used here is just the shader­toy builtin blue noise tex­ture, but 2 copies were added togeth­er at dif­fer­ent scales to make it effec­tive­ly one 16-bit noise tex­ture.

Conclusion

So that’s it as this is only a quick reac­tion post. To recap, the dither­ing prob­lem is com­pli­cat­ed by the fact that dis­play bright­ness in lin­ear in the num­ber of pix­els, but non-lin­ear in the RGB val­ue. Get­ting it right mat­ters for the low­est quan­ti­za­tion lev­els, be it either the dark parts of an image with many quan­ti­za­tion lev­els, or if there are only a few quan­ti­za­tion lev­els over­all.


以上所述就是小编给大家介绍的《Correct SRGB Dithering》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

网页艺术设计

网页艺术设计

彭钢 / 高等教育出版社 / 2006-9 / 39.00元

《网页艺术设计》将软件技术与艺术理论进行整合,注重知识性与研究性、实践性与理论性、系统性与逻辑性,全面介绍网页艺术设计的基础知识与基本实践技能,既培养学习者的网页技术应用能力,又培养学习者的艺术审美、艺术创新和研究性学习能力,使学习者在有效的课时内学习和掌握网页艺术设计的理论与实践。 《网页艺术设计》的特点是具有完整的知识结构、合理的教学设计以及立体化的教学资源。教材共分为8章,包括网页艺术......一起来看看 《网页艺术设计》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具