Color reduction changes colors unnecessarily

Post any defects you find in the released or beta versions of the ImageMagick software here. Include the ImageMagick version, OS, and any command-line required to reproduce the problem. Got a patch for a bug? Post it here.
Post Reply
Drarakel
Posts: 547
Joined: 2010-04-07T12:36:59-07:00
Authentication code: 8675308

Color reduction changes colors unnecessarily

Post by Drarakel »

This affects the storage of GIFs, but also manual color reductions.
(And it may be the origin of the problem of that thread.)

As example - a command that produces a 258x1 stripe with only 3 colors in it, once stored as BMP, once stored as GIF. The GIF has still 3 distinct colors, but some pixels have changed the color. Compare shows 6 shifted values with that:

Code: Select all

convert xc:grey66 xc:yellow -size 256x1 xc:darkgrey +append test.bmp
convert xc:grey66 xc:yellow -size 256x1 xc:darkgrey +append test.gif
compare -metric ae test.bmp test.gif null:
test.bmp correctly shows these color values:
# ImageMagick pixel enumeration: 258,1,255,rgb
0,0: (168,168,168) #A8A8A8 grey66
1,0: (255,255, 0) #FFFF00 yellow
2,0: (169,169,169) #A9A9A9 DarkGray
3,0: (169,169,169) #A9A9A9 DarkGray
...(all further pixels DarkGray)

But test.gif shows this:
# ImageMagick pixel enumeration: 258,1,255,rgb
0,0: (168,168,168) #A8A8A8 grey66
1,0: (255,255, 0) #FFFF00 yellow
2,0: (168,168,168) #A8A8A8 grey66
3,0: (168,168,168) #A8A8A8 grey66
4,0: (168,168,168) #A8A8A8 grey66
5,0: (168,168,168) #A8A8A8 grey66
6,0: (168,168,168) #A8A8A8 grey66
7,0: (168,168,168) #A8A8A8 grey66

8,0: (169,169,169) #A9A9A9 DarkGray
9,0: (169,169,169) #A9A9A9 DarkGray
...

My IM version is 6.6.1-7 Q16 - on Windows XP.

The colors are sometimes reduced and/or changed like that for GIFs with a few colors - at least if there are more than 256 pixels (with less than 256 pixels there is of course no need for color reductions). You will get different 'error counts' with different color values. The problem seems to be in the color reduction part - because the changes also show when you add "-colors 256" to the command and store as e.g. PNG.

Workarounds:
One can retain the correct values (only up to 256 colors of course) if one writes the files in two steps. First output as PNG8, then a simple "convert test.png test.gif" will do it.
Or: Applying a manual color reduction before writing as GIF seems to be ok - with dithering disabled. So, the command from above doesn't change the colors if done like that:
convert xc:grey66 xc:yellow -size 256x1 xc:darkgrey +append +dither -colors 256 test.gif
Last edited by Drarakel on 2010-05-11T08:44:29-07:00, edited 1 time in total.
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Color reduction changes colors unnecessarily

Post by anthony »

i have confirmed this bug in IM v6.6.1-7

Color counts...

Code: Select all

convert xc:grey66 xc:yellow -size 256x1 xc:darkgrey +append gif:- |  \
      convert - -format '%c' histogram:info:- 

Code: Select all

         7: (168,168,168) #A8A8A8 grey66
       250: (169,169,169) #A9A9A9 DarkGray
         1: (255,255,  0) #FFFF00 yellow
As three colors do appear in the output image, the Quantization step (select palette colors) would have successfully output all 3 colors. As such the error would have to be in the image re-coloring to the palette (which should be a no-op in this case as only palette colors are present. That is it would have to have been in a un-needed Dithering Step.

Hmmm getting the same error with no dither (+dither option)!

Code: Select all

convert xc:grey66 xc:yellow -size 256x1 xc:darkgrey +append +dither gif:- |  \
      convert - -format '%c' histogram:info:- 

Code: Select all

         7: (168,168,168) #A8A8A8 grey66
       250: (169,169,169) #A9A9A9 DarkGray
         1: (255,255,  0) #FFFF00 yellow
No Dither should have assign just the 'closest matching color' to each pixel. BUT as all colors are in the palette
all the color should have come out exactly as they are in memory.

That is definitely BAD! Even more so that the original problem (using the default Riemersma Dither).

Using a FloydSteinberg dither, the problem gets WORSE!!!!

Code: Select all

convert xc:grey66 xc:yellow -size 256x1 xc:darkgrey +append -dither FloydSteinberg gif:- |\
   convert - -format '%c' histogram:info:- 

Code: Select all

       257: (168,168,168) #A8A8A8 grey66
         1: (255,255,  0) #FFFF00 yellow
Now ALL the DarkGrey pixels have been replaced by grey66 pixels!!!!!
That is really really bad!
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
Drarakel
Posts: 547
Joined: 2010-04-07T12:36:59-07:00
Authentication code: 8675308

Re: Color reduction changes colors unnecessarily

Post by Drarakel »

Thanks for your confirmations!

Another example with the color reduction.. I always wondered why it's so difficult to write 8 bit per pixel BMPs (when there are already less than 256 colors). Well, that's off-topic.. But the thing is: I can use "-colors 256" to force it to 8bpp - but then some colors may be gone.

Take some greyscale image - for example this one:
http://h.imagehost.org/0317/grey.png
It has 236 colors (stored here as 3x8bit).

Now do a simple conversion:
convert grey.png -resize x500 grey2.png
"identify -format "%k" grey2.png":
256
(The resizing adds colors, but the maximum is 256 colors for this greyscale image. 'grey2.png' actually gets stored as 8bpp greyscale. Alright!)

This command should keep the 256 colors IMO:
convert grey.png -resize x500 -colors 256 grey2.bmp
"identify -format "%k" grey2.bmp":
64

2nd try:
convert grey.png -resize x500 +dither -colors 256 grey2b.bmp
"identify -format "%k" grey2b.bmp":
256
OK - but the result is still not the same as 'grey2.png'.
"compare -metric ae grey2.png grey2b.bmp null:":
4120
So, even "+dither -colors 256" does change the picture. The only workaround here is to store first as PNG/PNG8, then a "convert image.png image.bmp" does the trick.
:?

This example works the same way with GIF as output format. It can also be recreated with IM internal images.
Drarakel
Posts: 547
Joined: 2010-04-07T12:36:59-07:00
Authentication code: 8675308

Re: Color reduction changes colors unnecessarily

Post by Drarakel »

Bump.

You can ignore my last post.
(I still wonder why it's so difficult to write 8bit palette BMPs, but.. it's possible to create one that's identical to the PNG output with "convert grey.png -resize x500 -depth 8 -colors 256 grey2.bmp". So, the color reduction is ok there.)

But the first two posts here - from Anthony and me - are still valid.
With ImageMagick v6.6.2-5 Q16 on Windows XP, the problems with the GIF format and the color reduction are still there.

(By the way: Is there a version 6.6.2-6 for Windows..? I think, the file ImageMagick-6.6.2-6-Q16-windows-dll.exe is the same as v6.6.2-5.(?))

Just to repeat the basic test (no new hint here, sorry):

Code: Select all

convert xc:grey66 xc:yellow -size 256x1 xc:darkgrey +append -depth 8 PNG8:- | convert - -crop 10x1+0+0 +repage txt:-
convert xc:grey66 xc:yellow -size 256x1 xc:darkgrey +append -depth 8 GIF:-  | convert - -crop 10x1+0+0 +repage txt:-
as PNG8/BMP/etc.:
# ImageMagick pixel enumeration: 10,1,255,rgb
0,0: (168,168,168) #A8A8A8 grey66
1,0: (255,255, 0) #FFFF00 yellow
2,0: (169,169,169) #A9A9A9 DarkGray
3,0: (169,169,169) #A9A9A9 DarkGray
4,0: (169,169,169) #A9A9A9 DarkGray
5,0: (169,169,169) #A9A9A9 DarkGray
6,0: (169,169,169) #A9A9A9 DarkGray
7,0: (169,169,169) #A9A9A9 DarkGray
8,0: (169,169,169) #A9A9A9 DarkGray
9,0: (169,169,169) #A9A9A9 DarkGray

as GIF:
# ImageMagick pixel enumeration: 10,1,255,rgb
0,0: (168,168,168) #A8A8A8 grey66
1,0: (255,255, 0) #FFFF00 yellow
2,0: (168,168,168) #A8A8A8 grey66
3,0: (168,168,168) #A8A8A8 grey66
4,0: (168,168,168) #A8A8A8 grey66
5,0: (168,168,168) #A8A8A8 grey66
6,0: (168,168,168) #A8A8A8 grey66
7,0: (169,169,169) #A9A9A9 DarkGray
8,0: (169,169,169) #A9A9A9 DarkGray
9,0: (169,169,169) #A9A9A9 DarkGray
Post Reply