View this page in 4 colours / 8 colours / 16 colours
Imagemagick's color reduction algorithm is explained here.
Colorspace | No dithering | Dithered (Hilbert-Peano) | Original |
---|---|---|---|
RGB | |||
XYZ | |||
Grayscale | |||
YCC | |||
YIQ | |||
YUV | |||
LAB | |||
HSL |
The first row of the table shows a non-ordered dithering method, Hilbert-Peano, for comparison.
Dithering method | Grayscale | YCC | Original |
---|---|---|---|
Hilbert-Peano dithering | |||
o2x2 dithering | |||
o3x3 dithering | |||
o4x4 dithering | |||
o8x8 dithering | |||
h4x4a dithering | |||
h6x6a dithering | |||
h6x6o dithering | |||
checks dithering |
Neuquant does not do dithering by itself, but I added a Hilbert-Peano dithering to it by copying the algorithm from Imagemagick. The algorithm is a close variant of the Riemersma dithering algorithm. Also, it is stated that Neuquant is not optimized for working with a small number of colors.
Sampling factor | No dithering | Dithered (Hilbert-Peano) | Original |
---|---|---|---|
1 | |||
4 | |||
7 | |||
10 | |||
13 | |||
16 | |||
19 | |||
22 | |||
25 | |||
28 | |||
30 |
For some reason, filter size 1 resulted always in broken images, so it is excluded from this test.
Dithering level | Filter size = 3 | Filter size = 5 | Original |
---|---|---|---|
0.2 | |||
0.4 | |||
0.5 | |||
0.6 | |||
0.7 | |||
0.8 | |||
0.9 | |||
1.0 | |||
1.1 | |||
1.2 | |||
1.5 | |||
2 | |||
5 | |||
10 |
Because Gifsicle does not support reading of truecolor images, or actually any other images than GIF, I first reduced the image to 256 colors using Neuquant, and then converted it to GIF and gave it to Gifsicle for working. The result was converted to PNG.
Method | No dithering | Dithering (floyd-steinberg) | Original |
---|---|---|---|
Median-cut, aka. Heckbert algorithm | |||
Diversity | |||
Blend-diversity |
Scolorq, Filter 3, dither level 0.7 |
Scolorq, Filter 5, dither level 0.8 |
Imagemagick at grayscale, dithered |
The author wondered for a long time why no tool discoved the best of both worlds, where the buruma would be blue and the bracelets would be red, but then realized that there's simply not enough colors.
# Gifsicle tests: scolorq original.jpg neuquant-256c-q30.png -q30 -c256 mogrify -format gif neuquant-256c-q30.png gifsicle -o gifsicle-4c-mc-dith.gif -f -k4 --color-method median-cut \ neuquant-256c-q30.gif gifsicle -o gifsicle-4c-di-dith.gif -f -k4 --color-method diversity \ neuquant-256c-q30.gif gifsicle -o gifsicle-4c-bd-dith.gif -f -k4 --color-method blend-diversity \ neuquant-256c-q30.gif gifsicle -o gifsicle-4c-mc-nodith.gif -k4 --color-method median-cut \ neuquant-256c-q30.gif gifsicle -o gifsicle-4c-di-nodith.gif -k4 --color-method diversity \ neuquant-256c-q30.gif gifsicle -o gifsicle-4c-bd-nodith.gif -k4 --color-method blend-diversity \ neuquant-256c-q30.gif mogrify -format png gifsicle-4c-{mc,di,bd}-{nodith,dith}.gif # Scolorq tests: for f in 1 3 5;do \ for d in 0.2 0.4 0.5 0.6 0.7 0.8 0.85 0.9 1.0 1.1 1.2 1.5 2 3 5 10 20 30 50;do \ scolorq original.jpg scolorq-4c-f"$f"-d"$d".png -f$f -d$d -c4;done;done # Neuquant tests: for s in `seq 0 30`;do \ scolorq original.jpg neuquant-4c-q$s.png -q$s -c4;done # Imagemagick tests: for s in rgb yuv ycc xyz yiq hsl lab gray;do \ convert original.jpg -quantize $s -depth 8 \ +dither -colors 4 imagemagick-4c-$s-nodith.png;done for s in rgb yuv ycc xyz yiq hsl lab gray;do \ convert original.jpg -quantize $s -depth 8 \ -colors 4 imagemagick-4c-$s-dith.png;done for d in o2x2 o3x3 o4x4 o8x8 h4x4a h6x6a h8x8a h4x4o h6x6o h8x8o h16x16o checks;do for s in rgb yuv ycc xyz yiq hsl lab gray;do \ convert original.jpg -quantize $s -depth 8 \ -ordered-dither $d -colors 4 imagemagick-4c-$s-$d.png;done done
The package containing my custom version of scolorq that also includes the neuquant algorithm, can be downloaded here: http://bisqwit.iki.fi/src/arch/scolorq_and_neuquant-1.0.0.tar.bz2. It requires libGD.
The images produced by the tests were optimized losslessly for small size using AdvanceCOMP and PNGOUT.
The version of Imagemagick used was 6.3.5. Note that version 6.2.4 does not support the -quantize and -ordered-dither parameters in the way used by this script.