Identify dominant colors in an image

Deeply inspired by a tweet I saw a couple of days ago, where @NASAGoddard teamed up with @colourlovers to identify colors in satellite images, I set out to write a script that did this with any image.

UPDATE: Try it now online at http://apps.hoyd.net/hexcolors/

I have been using Sentinel Hub to spot beautiful places on Earth for a while, so it felt natural to try out my own set of satellite imagery.

As a long time Linux user, scripting kind of comes naturally, but I often look up not so often used commands. I knew the package ImageMagick has a few sweet commands, for example convert. Combined with bash-programming, this shouldn’t be to complicated.

The script can be found at GitHub and at the bottom of this post, but be advised, it it a simple approach and could break easily. It should work fine on pictures equal to or bigger than 1080×720 pixels wide as the code resize and crop the image to fit the predefined color box row.

A set of test images

The script hex-colors.sh take an image file as argument and will identify the five most dominant colors from that image. Storing the hex values of the colors in a text file, it loops over those colors and creates a rectangles for each with the hexadecimal color code in those rectangles.

The script then combines the rectangles into one and then appends the combined image with the original one stacked. The script then deletes the temporary files and you are left with the original and the new version with colors identified.

Here are the colors from the set above identified

The code

#!/bin/sh

# CROP IMAGE INTO HD FORMAT 1080X720 FROM CENTRE
convert $1 -resize 1080x1080 resized-$1
convert resized-$1 -gravity center -crop 1080x720 cropped-$1

# GET FIVE MOST DOMINANT HEX COLORS FROM ANY IMAGE
convert cropped-$1 +dither -colors 5 -unique-colors txt: | awk '{ print $3 }' | grep '#' > hex.tmp

# CREATE A RECTANGLE FROM EACH HEX COLOR WITH HEX CODE AS TEXT IN THE MIDDLE
while read p; do
  convert -size 216x144 xc:$p rect-$p.png
  convert -background '#0008' -fill white -gravity center -size 216x30 caption:$p rect-$p.png +swap -gravity south -composite rect-$p.png
done <hex.tmp

# COMBINE RECTANGLES INTO ONE COMBINED IMAGE
convert +append rect-*.png combined.png

# APPEND COMBINED IMAGE BELOW THE ORIGINAL IMAGE
convert -append cropped-$1 combined.png $1-colors.jpg

# REMOVE TEMPORARY FILES
rm hex.tmp rect* cropped-$1 resized-$1 combined.png

When I see things like that tweet, I often start to think how to do these things and if it doesn’t feel to complicated, I can’t help but trying to implement a solution.