Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dithering methods #279

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open

Conversation

roshavagarga
Copy link

@roshavagarga roshavagarga commented Jan 10, 2024

Changes:

  1. Changed all dither names to typically used informal/formal ones.
  2. Removed decimal points from matrices - these seemed to serve no purpose.
  3. Renamed and rearranged all dithers - publication date to modification and error diffusion vs ordered.
  4. Added 10 new dithers - Fan, Shiau–Fan, Shiau–Fan 2, Sierra, Sierra (Two-row), Bayer (3x3), Bayer (8x8), Cluster Dot (4x4), Halftone (8x8), Void and cluster (14x14).
  5. Switched from dashes to en dashes for names, wherever applicable.

New list of dithering methods:

  1. Floyd–Steinberg - 1976
  2. Atkinson - Floyd–Steinberg modification, 1980s
  3. Sierra (Filter Lite) - Floyd–Steinberg modification, 1990
  4. Fan - Floyd–Steinberg modification, 1993/1994
  5. Shiau–Fan - Floyd–Steinberg modification, 1993/1994
  6. Shiau–Fan 2 - Floyd-Steinberg modification, 1993/1994
  7. Jarvis–Judice–Ninke - 1976
  8. Stucki - Jarvis–Judice–Ninke modification, 1981
  9. Burkes - Stucki modification, 1988
  10. Sierra - Jarvis–Judice–Ninke modification, 1989
  11. Sierra (Two-row) - Sierra modification, 1990
  12. Bayer 2x2
  13. Bayer 3x3
  14. Bayer 4x4
  15. Bayer 8x8
  16. Ordered (3x3)
  17. Cluster Dot (4x4)
  18. Halftone (8x8)
  19. Void and cluster (14x14)

Sources for above:
https://community.wolfram.com/groups/-/m/t/1383824
https://momentsingraphics.de/BlueNoise.html
https://surma.dev/things/ditherpunk/
https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html
https://en.wikipedia.org/wiki/Dither
https://www.researchgate.net/figure/Error-diffusion-scheme-for-different-dithering-algorithms-Floyd-Steinberg-a-Jarvis_fig1_347225976
https://www.visgraf.impa.br/Courses/ip00/proj/Dithering1/ordered_dithering.html
https://beyondloom.com/blog/dither.html
https://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/dither/dither.pdf
http://caca.zoy.org/study/part3.html
https://cs.wellesley.edu/~pmetaxas/ei99.pdf
https://cs.wellesley.edu/~pmetaxas/pdcs99.pdf
https://www.iro.umontreal.ca/~ostrom/varcoeffED/SIGGRAPH01_varcoeffED.pdf
https://web.archive.org/web/20190316064436/http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT
https://core.ac.uk/reader/327118630
https://github.com/robertkist/libdither/blob/main/src/libdither/dither_errordiff_data.h
https://bisqwit.iki.fi/jutut/kuvat/ordered_dither/error_diffusion.txt
https://devlog-martinsh.blogspot.com/2011/03/glsl-8x8-bayer-matrix-dithering.html

Switched to proper names, per identified sources/typical names.
Decimal points were pointless and making the matrices harder to read.
2x3 matrix
2x5 matrix
Changed to Sierra (Filter Lite)
Was still listed as MinAvgErr
UniqueIDs should probably match ones in ditherMethods.js
Forgot to update the uniqueID name
Based on year of publication, variant/derivations and error diffusion vs ordered
Possibly pointless, who knows
Added Fan, Shiau-Fan, Shiau-Fan 2, Sierra and Sierra (Two-row)
Possibly pointless yet again, but who knows
From normal dash to en dash, wherever appropriate
@roshavagarga
Copy link
Author

@rebane2001 Just a quick heads up - I am not a developer/programmer, but the above seemed simple enough to implement.

I don't have a way of testing any of the above, but I imagine that the changes I made should improve certain things as far as code readability, and other things as far as actual images/previews - I believe there were 1-2 matrices that had errors on top of the fluff I removed.

The dither methods I added are all pre-2020 and do not have active patents, thus are free to use. Since they are derivations of others present in the list, they should also offer some improvements.

If anything was changed erroneously and you think I can fix it - please highlight the issue and I will try my best.

Because somebody made a mistake
Mistakes were made ¯\_(ツ)_/¯
Stevenson–Arce - hexagonal 7x4, 1985;
Added new dither method;
@roshavagarga
Copy link
Author

Added another dither method - Stevenson–Arce (1985), hexagonal, 7x4 matrix.

I don't plan on adding anything else at this point, unless requested to.

@roshavagarga
Copy link
Author

roshavagarga commented Jan 16, 2024

Fixed Stevenson-Arce (duplicate uniqueID), added Bayer 3x3 and 8x8 (added +1 to every point compared to typical matrices, as previously done).

Current issues:

  1. Broken matrices, unclear exactly why, but related to removed lines/buffers somehow:
  • Floyd–Steinberg
  • Atkinson
  • Sierra (Filter Lite)
  • Fan
  • Shiau–Fan

Note: Did not bug out all changed matrices, again - unclear why.

  1. Removing decimals off divisors changes dither result.

@Emix33
Copy link

Emix33 commented Jan 17, 2024

I can answer some of the questions/issues that you ran into.

Regarding 1:
Removing lines from the matrices breaks them because all matrices used for non ordered dither are assumed to be fixed size (5x3). This is because we need to know which pixels relative to the original pixel we need to shift the error to.
So when you have a matrix like:
[0,0,X,0,0]
[0,0,0,0,0]
[0,0,0,0,0]
X always refers to the origin pixel. (That is also why the first 3 pixels in this type of matrix should be 0, as you cant diffuse an error to pixels you already have processed)
If you want to use matrices with different sizes/origin pixel you need to adjust the algorithm used for applying the error diffusion. (Ordered Dithering uses a different algorithm and is thus not affected)

Regarding 2:
Javascript has both integers (-1, 0, 1, 2 ...) and floats (0.5, 1.2, -3.7). When you have a division with at least one float: 7.5 / 2.5 you would get 3.0 and when you have 8 / 3.0 you would get 2.6666 (not exact, but close enough). When you try to divide an integer by another integer: 8 / 3 you would get another integer (always rounded down, even if up would be closer) so in this case 2. This is obviously extremely far off from the original value and will change the result massively expecially when the value is used in further calculations.

@roshavagarga
Copy link
Author

@Emix33 Thank you for the information! That does explain a lot.

Now, excuse these follow-up questions, but I am curious:

  1. Per your explanation, either the algorithm needs to be changed, or the previously-removed buffer rows/columns will need to be added back in - do you think the results would differ? As in, which method would provide better/more accurate dithering.

I will fiddle with the matrices on my own, but per the current setup, it seems that 5x2 matrices still work, despite removing the last row - I think I compared these and they were giving the same output, but will recheck.

  1. If I'm understanding you correctly, the best option quality-wise would be to leave the divisors as floats, but have the matrices be done as integers, right? Again, I'm going off my bad memory, but I think comparisons showed that Burkes and Jarvis were giving the same results despite me changing the matrices to integers and removing their buffer rows.

  2. Stevenson-Arce seemingly works for me, but if it is being read as a 5x3 (rather than the 7x4 it is), then some of it is not being handled/used properly, correct?

That would explain some obvious dithering patterns I saw, which I chalked up to the matrix itself, rather than to an error on my part.

  1. Performance-wise, for the website/calculations, would it be better to do the buffer rows/columns, or implement a new algorithm - I've noticed slower calculations when running locally and wasn't sure why, though that may be because the matrices I was using weren't 5x3.

Again, thank you for the input, anything else would be greatly appreciated.

Sort of?
Hopefully no more sequels to this
Cluster dot 4x4, Halftone 8x8, Void and cluster 14x14
Same dither result, calculation speeds up;
@roshavagarga
Copy link
Author

roshavagarga commented Jan 19, 2024

With the above commits, all dithers now work, added a few more ordered ones via derived matrices from the Libcaca study.

Added:

  • Cluster Dot 4x4
  • Halftone 8x8
  • Void-and-cluster 14x14 (unclear if it should be done on the fly or via set matrix, but it seemingly gives good results)

Fixed:

  • Floyd–Steinberg
  • Atkinson
  • Sierra (Filter Lite)
  • Fan
  • Shiau–Fan

Other:

  • Added back padding/buffer row and columns where needed - does not change dither result, but speeds up calculations.

Issues:

  1. Unclear if the current way of handling is accurate or not. Specifically, there is a high chance that Stevenson–Arce is inaccurate, as its matrix size is above 5x3, thus possibly only part of it is handled? If it's not that simple to fix - can be dropped, although even if it is inaccurate currently, it gives interesting results in some cases.
  2. If void-and-cluster method needs to be done on-the-fly/per-image, matrix is a stopgap and an external script can be included to do the calculations - there are free blue noise filters + scripts across Github and in the links above.

Wrong matrix, plus hexagonal vs square pixels;
@roshavagarga
Copy link
Author

Removed:

  • Stevenson–Arce

The matrix I used was off, but even if it hadn't been wrong, it would have given bad results, as it was created for hexagonal pixels, rather than square ones, thus is would have given bad results.

This should clean up the last issues - PR is ready for review/merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants