Generate color palette from image with ImageMagick
Asked Answered
S

2

19

I need to generate a color palette of the top 5 dominant colors in an image. I'd like to replicate the results of Embedly's extract tool or Color Thief.

The following command gives me slightly different results:

convert testimage.jpg  -format %c -colorspace LAB -colors 5 histogram:info:- | sort -n -r
    157154: ( 19, 28, 35) #131C23 srgb(19,28,35)
     16164: ( 27, 51, 77) #1B334D srgb(27,51,77)
     15725: ( 79, 88, 84) #4F5854 srgb(79,88,84)
      8608: ( 44, 77,103) #2C4D67 srgb(44,77,103)
      5149: ( 84,126,150) #547E96 srgb(84,126,150)

I'm a bit unsure if I should quantize to 5 colors as I've found that doing so doesn't work so well with simple graphics (for example the Google logo). Is it better to use a larger color palette and then just select the top n colors?

This leads me on to my next question regarding the quantization algorithm used. Looking at the results of Embedly Extract, the output colors are not necessarily the most frequent but appear to be the clusters that are the most different from each other.

For example suppose I have a very dark image (black/browns) with a small detail in bright red. How would I ensure that ImageMagick includes the red? (apologies if this sounds dumb, color theory is all new to me!).

Below is the image I've been using for testing:

enter image description here

Scarlatina answered 12/11, 2014 at 14:28 Comment(0)
B
29

Can you define "top 5 dominant colors", please? I think this isn't as easy as it sounds...

This is clearly shown by the different results which can be seen when visiting the links you provided for Embed.ly's and for Color Thief's interpretation of your test image.

Embed.ly

Here is what Embed.ly lists as its 5 extracted colors (I looked at the HTML source code of the page to find out):

 rgb(13, 28, 37)
 rgb(44, 74, 94)
 rgb(71, 112, 131)
 rgb(105, 147, 163
 rgb(198, 209, 216)

Use ImageMagick to create a color palette with these 5 colors:

 convert                        \    
     -size 60x60                \    
      label:"        Embed.ly"  \
      xc:"rgb(13, 28, 37)"      \    
      xc:"rgb(105, 147, 163"    \    
      xc:"rgb(71, 112, 131)"    \    
      xc:"rgb(44, 74, 94)"      \    
      xc:"rgb(198, 209, 216)"   \
     +append                    \    
      embedly-palette-from-testimage.jpg

Look at the result:

Embed.ly's pick of 5 colors...

Color Thief

Color Thief names one color as the "dominant" color:

 rgb(21, 30, 38)

Color Thief also lists a palette of 9 more colors (again, values retrieved from HTML source code):

 rgb(18, 27, 35)
 rgb(100, 142, 164) 
 rgb(51, 84, 110) 
 rgb(32, 53, 74)
 rgb(47, 46, 43)
 rgb(83, 85, 76)
 rgb(145, 143, 128) 
 rgb(106, 141, 140) 
 rgb(62, 84, 81)

Use ImageMagick to create a color palette with Color Thief's 9 pallete colors:

 convert                        \    
     -size 60x60                \    
      label:"     Color Thief"  \
      xc:"rgb(18, 27, 35)"      \    
      xc:"rgb(100, 142, 164)"   \
      xc:"rgb(51, 84, 110)"     \    
      xc:"rgb(32, 53, 74)"      \    
      xc:"rgb(47, 46, 43)"      \    
      xc:"rgb(83, 85, 76)"      \    
      xc:"rgb(145, 143, 128)"   \
      xc:"rgb(106, 141, 140)"   \
      xc:"rgb(62, 84, 81)"      \    
     +append                    \    
      ct-palette-from-testimage.jpg

Look at the result:

Color Thief's palette of 9 extracted colors...

Color Thief is based on quantize.js. It uses the median cut algorithm provided by quantize.js to cluster similar colors and then returns the base color from the largest cluster as the "dominant" color.

How it determines which colors to return as "palette colors" can be determined from its source code, which is hosted on Github.

ImageMagick's 5 quantized colors

Your question lists the output of ImageMagick's histogram after quantizing the image to 5 colors only.

Use these 5 colors to create another color palette:

 convert                        \
     -size 60x60                \
      label:"   ImageMagick"    \
      xc:"srgb(19,28,35)"       \
      xc:"srgb(79,88,84)"       \
      xc:"srgb(44,77,103)"      \
      xc:"srgb(27,51,77)"       \
      xc:"srgb(84,126,150)"     \
     +append                    \
      im-palette-from-testimage.jpg

Look at the result:

ImageMagick's 5 quantized colors...

Compare 3 color palettes

Use this command to create a visual comparison of the 3 color palettes:

 convert                                    \
      ct-palette-from-testimage.jpg         \
      embedly-palette-from-testimage.jpg    \
      im-palette-from-testimage.jpg         \
     -append                                \
      color-palettes.jpg

Result:

Direct visual comparison of 3 created color palettes...

As can clearly be seen, neither Color Thief nor the 5 quantized colors from ImageMagick's histogram do include the rather bright 5th color returned by Embed.ly.

Compare again to your test image:

Test image...

"Is it better to use a larger color palette and then just select the top n colors?"

Why don't you test it and find out yourself?

Burr answered 13/11, 2014 at 19:32 Comment(5)
I've since tried this using modified median cut quantization (MMCQ) and am getting results much closer to that of embedly's service. According to the white paper this gives better results for images with highly visible but low population colors.Scarlatina
I don't think telling someone to test something and "find out themselves" is really appropriate for a Q&A site.Gillan
@Skrylar: But I do think so. Because the sub-answer to the sub-question which got this comment from me is heavily colored by personal preferences. My complete answer empowers the original poster to run all the tools and commands which help him generate the visual output he can then look at and find out himself what his personal answer is to that sub-question "Is it bettter...?", because that very likely will be different from my respective answer...Burr
With this image, I find that color-thief (more exactly, color-thief-jimp) results in more vibrant and varied colors overall (including more green where imagemagick found little), and imagemagick gives more distinct and varied blues. It seems like embed.ly may be better at finding brighter colors. I'd give a screen shot but that's not working for me now for some reason.Neckband
Alas! This answer today received a downvote. It would be nice, dear downvoter, if you could also submitted a comment explaining what you didn't like about the answer, or with which of its aspects you do not agree with.Burr
S
7

This is a bit of a hack, but here's what I do:

  • scale the image down to 8x8 or 16x16,
  • limit colour depth to 16 or 24 or 32
  • select unique colours from the scaled image and dump them into a file

This forces Image Magick to create a basic sample of colours, and then selects those and places them into a colour swatch array.

Using Ben's example photo, here's the command and results:

convert image.png -geometry 16x16 -colors 32 \
-unique-colors -scale 4000% scheme.png

imagemagick

Svetlana answered 6/7, 2018 at 5:42 Comment(1)
I won't downvote this answer, even if it doesn't take into account of the OP's request to get the five dominant colors and instead returns 9 different colors... (Also, the rules of this website do not require to downvote other answers when you add your own one to a question.)Burr

© 2022 - 2024 — McMap. All rights reserved.