Correct SRGB Dithering

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

内容简介: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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Release It!

Release It!

Michael T. Nygard / Pragmatic Bookshelf / 2007-03-30 / USD 34.95

“Feature complete” is not the same as “production ready.” Whether it’s in Java, .NET, or Ruby on Rails, getting your application ready to ship is only half the battle. Did you design your system to......一起来看看 《Release It!》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具