virtualritz 7 days ago

The dithered images have the wrong brightness mapping.

The reason is that the described approach will estimate the error correction term wrong as the input RGB value is non-linear sRGB.

The article doesn't mention anything about this so I assume the author is oblivious to what color spaces are and that an 8bit/channel RGB value will most likely not represent linear color.

This is not bashing the article; most people who start doing anything with color in CG w/o reading up on the resp. theory first get this wrong.

And coming up with your own dither is always cool.

See e.g. [1] for an in-depth explanation why the linearization stuff matters.

[1] http://www.thetenthplanet.de/archives/5367

2
venusgirdle 7 days ago

Hi, OP here!

Thank you so much for pointing this out! Just read the post you linked and did some of my own research on the non-linearity of sRGB - really fascinating stuff :)

For now, I've acknowledged this limitation of my implementation so that any new readers are aware of it: https://amanvir.com/blog/writing-my-own-dithering-algorithm-...

But I'll definitely revisit the article to add proper linearization to my implementation when I have the time. Thanks again for mentioning this!

DistractionRect 7 days ago

You're already 99% of the way there, you're just have the order of operations wrong.

What you're doing is sRGB -> linear perceived luminance space -> sRGB (greyscale, where R=G=B) -> dithering

When you should be applying dithering in the linear perceived luminance space, then covering the dithered image back into sRGB space.

virtualritz 7 days ago

It's not about order of operations; there is simply no linearization of sRGB happening or mentioned in the article.

I.e. it's not ordering of operation but absence of an operation that is the issue.

> ... -> linear perceived luminance space -> ...

"Perceptual" luminance is not a concept used anywhere. Luminance is, by definition, linear [1].

When we talk about color, something can either be linear or perceptual. Not both. "Perceptual" refers to "how humans perceive something" and the human visual system is non-linear.

Relative luminance [2] (what people refer to as grayscale) and what we're dealing with in the post, is still linear. So the order of operations is:

sRGB non-linear -> sRGB linear -> grayscale -> dither

After the dithering no conversion back to sRGB is necessary for the case at hand because all pixels are black or white and the sRGB transfer function for the inputs 0 and 1 has the outputs 0 and 1.

See also [3]. You only would re-apply a sRGB linear -> sRGB non-linear transform if you didn't dither to black and white after the grayscale conversion. I.e. in the case at hand: if you dithered the 8bit grayscale to n bit grayscale with 1 < n < 8.

[1] https://en.wikipedia.org/wiki/Luminance

[2] https://en.wikipedia.org/wiki/Relative_luminance

[3] https://en.wikipedia.org/wiki/Grayscale#Colorimetric_(percep...

DistractionRect 7 days ago

You're absolutely right. I skimmed and misread.

danielvf 7 days ago

To some extent I think this comes down to a preference, like many things in dithering. If the black and white results look good, that may be the right answer!

I've played with dithering tools that provide both options, and I prefer the output of the simple version..

venusgirdle 7 days ago

Haha, yeah I was kind of thinking that as well! Like with different error-diffusion patterns, one method may be more visually appealing than the other.

Although, with either approach, I definitely feel that the fact that sRGB is non-linear should be acknowledged, and that’s something I was completely unaware of. So, I’m happy I learned something new today :)

Lerc 7 days ago

Are dithering patterns proportional in perceived brightness to a uniform grey for any percentage of set pixels?

I can see them not being linearly proportional to a smooth perceptual grey gradient as the ratio of black to white changes, but I suspect it might change also with the clustering of light and dark at the same ratio.