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:
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:
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 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:
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:
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:
"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?