NHacker Next
  • new
  • past
  • show
  • ask
  • show
  • jobs
  • submit
Writing my own dithering algorithm in Racket (amanvir.com)
crazygringo 3 minutes ago [-]
> Atkinson dithering is great, but what's awesome about dithering algorithms is that there's no definitive "best" algorithm!

I've always wondered about this. Sure, if you're changing the contrast then that's a subjective change.

It's easy to write a metric to confirm the degree to which brightness and contrast are maintained correctly.

But then, is it really impossible to develop an objective metric for the level of visible detail that is maintained? Is that really psychovisual and therefore subjective? Is there really nothing we can use from information theory to calculate the level of detail that emerges out of the noise?

neilv 6 minutes ago [-]
(Kudos on doing this in Racket. Besides being a great language to learn and use, using Racket (or another Scheme, or other less-popular language) is a sign that the work comes from genuine interest, not just pursuit of keyword employability.)

Side note on Lisp formatting: The author is doing a mix of idiomatic cuddling of parenthesis, but also some more curly-brace-like formatting, and then a cuddling of a trailing small term such that it doesn't line up vertically (like people sometimes do in other languages, like, e.g., a numeric constant after a multi-line closure argument in a timer or event handler registration).

One thing some Lisp people like about the syntax is that parts of complex expression syntax can line up vertically, to expose the structure.

For example, here, you can clearly see that the `min` is between 255 and this big other expression:

    (define luminance
      (min (exact-round (+ (* 0.2126 (bytes-ref pixels-vec (+ pixel-pos 1)))   ; red
                           (* 0.7152 (bytes-ref pixels-vec (+ pixel-pos 2)))   ; green
                           (* 0.0722 (bytes-ref pixels-vec (+ pixel-pos 3))))) ; blue
           255))
Or, if you're running out of horizontal space, you might do this:

    (define luminance
      (min (exact-round
            (+ (* 0.2126 (bytes-ref pixels-vec (+ pixel-pos 1)))   ; red
               (* 0.7152 (bytes-ref pixels-vec (+ pixel-pos 2)))   ; green
               (* 0.0722 (bytes-ref pixels-vec (+ pixel-pos 3))))) ; blue
           255)))
Or you might decide those comments should be language, and do this:

    (define luminance
      (let ((red   (bytes-ref pixels-vec (+ pixel-pos 1)))
            (green (bytes-ref pixels-vec (+ pixel-pos 2)))
            (blue  (bytes-ref pixels-vec (+ pixel-pos 3))))
        (min (exact-round (+ (* red   0.2126)
                             (* green 0.7152)
                             (* blue  0.0722)))
             255)))
One of my teachers would still call those constants "magic numbers", even when their purpose is obvious in this very restricted context, and insist that you bind them to names in the language. Left as an exercise to the reader.
Aryezz 2 hours ago [-]
Great read and nice drawings!

I made some impractical dithering algorithms a while ago, such as distributing the error to far away pixels or distributing more than 100% of the error: https://burkhardt.dev/2024/bad-dithering-algorithms/

Playing around with the distribution matrices and exploring the resulting patterns is great fun.

_ache_ 2 hours ago [-]
Nice ! Thank you for the link! :)
qwertox 53 minutes ago [-]
Somewhat related and worth watching:

Surface-stable fractal dithering explained

https://youtu.be/HPqGaIMVuLs

There's a follow-up video to that one.

lampiaio 7 minutes ago [-]
Wouldn't it make more sense to display the samples at 100% in the article? Had to open the images in a new tab to fully appreciate the dithering.
_ache_ 2 hours ago [-]
I did the same like 2 weeks ago. In Rust. ^^

I'm still trying to improve it a little. https://git.ache.one/dither/tree/?h=%f0%9f%aa%b5

I didn't published it because it's hard to actually put dithered images on the web, you can't resize a dithered image. So on the web, you have to dither it on the fly. It's why, in the article, there is some artifacts in the images. I still need to learn about dithering.

Reference: https://sheep.horse/2022/12/pixel_accurate_atkinson_ditherin...

Cool links about dithering: - https://beyondloom.com/blog/dither.html - https://blog.maximeheckel.com/posts/the-art-of-dithering-and...

01HNNWZ0MV43FF 45 minutes ago [-]
Why can't you resize it? Because of the filtering? You can turn that off in css, right?
pixelpoet 2 hours ago [-]
The thresholding should be done in linear space I think, not directly on the sRGB encoded values.

Also I think the final result has some pretty distracting structured artifacts compared to e.g. blue noise dithering.

v9v 2 hours ago [-]
I love the small image previews to the left of the lines of code loading and saving images. Which editor is this?
venusgirdle 2 hours ago [-]
I love them too :)

Visual Studio Code with this extension: https://marketplace.visualstudio.com/items/?itemName=kisstko...

jansan 49 minutes ago [-]
I think implementing a dithering algorithm is one of the most satisfying projects, because it is fun, small(ish) and you know when you are done.

Of course, unless you are trying to implement something completely insane like Surface-Stable Fractal Dithering https://www.youtube.com/watch?v=HPqGaIMVuLs

turnsout 2 hours ago [-]
This is awesome! But be careful, if you dig much further you're going to get into blue noise, which is a very deep rabbit hole.
57 minutes ago [-]
Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact
Rendered at 21:52:23 GMT+0000 (Coordinated Universal Time) with Vercel.