This project has moved and is read-only. For the latest updates, please go here.

Quantization & Unique (Dominant) Colors

Aug 18, 2014 at 5:09 PM
I'm trying to reduce the colors of an image to 8 dominant colors, and I have a picture of a rainbow here:

Image

I've got code like this:
var qSettings = new QuantizeSettings { Colors = 8, DitherMethod = DitherMethod.No, ColorSpace = ImageMagick.ColorSpace.RGB};
imageMagick.Quantize(qSettings);
                
imageMagick.Write("c:\\work\\test.png");
No matter what combination I try (changing the ColorSpace, modifying TreeDepth, etc.), it will always merge at least two of the bars together. usually red and orange or dark blue and violet.

I was using MagickNet 6.8.9.601, but I just switched to 7.0.0.0001 to see if that would help anything. It didn't. Why does Quantize do that? Do you have any advice or suggestions?
Aug 18, 2014 at 5:58 PM
I have determined that the following IM command produces the same incorrect result:

convert rainbow.png -dither None -colors 8 test2.png

So I don't think the issue is with MagickNet, but I don't know how to get ImageMagic or MagickNet to do what I want. Any help would be appreciated.
Aug 18, 2014 at 6:11 PM
To further this, I've found that Quantize inherently does not pick primary colors. I just wish there was some better way to figure this out. Photoshop can do it easily:

Mode -> Indexed
8 colors
Local Selective Palette
Nothing Forced

That generates a perfect specimen. I just want to do the same thing, but Quantize is ruining it by picking what it thinks is best to represent the image and choosing poorly.
Aug 18, 2014 at 10:20 PM
Edited Aug 18, 2014 at 10:21 PM
If you want to use the most dominant colors you are probably better of using the map method:
// Read source image.
using (MagickImage image = new MagickImage(@"D:\images\png\rainbow.png"))
{
  // Create collection to store top 8 colors.
  using (MagickImageCollection colors = new MagickImageCollection())
  {
    // Get the histogram of the image (key = color, value = count).
    Dictionary<MagickColor, int> histogram = image.Histogram();

    // Add the 'top 8 colors' to the collection.
    foreach (MagickColor color in (from c in histogram
                                   orderby c.Value descending
                                   select c.Key).Take(8))
    {
      colors.Add(new MagickImage(color, 1, 1));
    }

    QuantizeSettings settings = new QuantizeSettings
    {
      // Due to a bug you have to set it to null instead of DitherMethod.No.
      // This will be fixed in next release.
      DitherMethod = null
    };

    // Create a color map with the 'top 8 colors'.
    using (MagickImage colorMap = colors.AppendHorizontally())
    {
      // Map image to the colors in the color map.
      image.Map(colorMap, settings);
    }
  }

  // Save output
  image.Write(@"D:\images\png\rainbow-8-colors.png");
}
Output: https://www.dropbox.com/s/r9q74nqji6kdk9w/rainbow-8-colors.png
Aug 18, 2014 at 11:28 PM
Well, that works great for the rainbow, but fails for all my other "normal" cases, like a room scene or a grassy hill, where it just returns all browns or greens and nothing else. My ultimate goal is to be able to pull the perceived dominant colors like here:
http://lokeshdhakar.com/projects/color-thief/
Aug 19, 2014 at 12:20 PM
Maybe you should ask your question here: http://www.imagemagick.org/discourse-server/index.php? They might have some better ideas. I will help you translate it once we get the 'correct' command line arguments.