indexpost archiveatom feed syndication feed icon

Scraping Color Palettes

2016-03-24

I wrote previously about scraping "fashionable" sites to derive some sense of web trends. What I'd like to work on now is extracting a palette from those images in an effort to hone my sense of color.

Down to Business

I'm not going to rehash how I scraped those images, I'll be operating in the same directory structure as before. I am using imagemagick again here, the more I discover of it the more impressed I am. The convert command is capable of capturing a histogram in a given colorspace1 for an image. Here I am getting a histogram of the top 5 colors in the image:

  convert ./images/56d4a5cc61223.jpeg \
          -colorspace LAB -colors 5 \
          -format %c histogram:info:-
    106616: ( 74, 62, 50) #4A3E32 srgb(74,62,50)
     39165: (101,140, 82) #658C52 srgb(101,140,82)
     41859: (171,149,106) #AB956A srgb(171,149,106)
     54092: (187,175,159) #BBAF9F srgb(187,175,159)
    108268: (249,248,245) #F9F8F5 srgb(249,248,245)

Based on this image:

sample website

Extracting the Useful Parts

The inclusion of standard hex color-codes is convenient, so I'll parse that out. I'm doing some ugly text hacking here to generate an HTML div only for the sake of convenience. I'm also sorting the first column which represents a count of the number of pixels of that color, by sorting on it I get an ordered list of the most prominent colors.

  echo "<div class=\"palette-2a458\">";
  convert ./images/56d4a5cc61223.jpeg \
            -colorspace LAB -colors 5 \
            -format %c histogram:info:- \
  | sort -rn \
  | gsed 's/.*\(#[0-9A-F]\{6\}\).*/\1/' \
  | sed -e 's/^/<div class="swatch-7a4be" style="background-color:/' \
        -e 's/$/\"><\/div>/';
  echo "</div>";

Test Run

The results aren't perfect, they fail to account for some small but visually striking colors, which I think means I would need to incorporate something like a K-means clustering to do a better job. But I'm not unhappy with the results so far. Just for fun, let's take it down to the top 4 colors and run it against a random sample of 4 images to check it out:

  swatch() {
      echo "<img class=\"reference-3ca8d\" src=\"$1\"></img>";
      echo "<div class=\"palette-2a458\">";
      convert "$1" \
              -colorspace LAB \
              -colors 4 \
              -format %c histogram:info:- \
          | sort -rn \
          | gsed 's/.*\(#[0-9A-F]\{6\}\).*/\1/' \
          | sed -e 's/^/<div class="swatch-7a4be" style="background-color:/' \
                -e 's/$/\"><\/div>/';
      echo "</div>";
  }

  export -f swatch

  find ./images -type f | gshuf | head -n4 | xargs -I{} bash -c 'swatch "$@"' _ {}

Not bad! This is pretty much what I envisioned in the first place so I can't complain about the results. I think I'll take a stab at clustering if I get a chance, if only to see how different the results are. It should be easier now that I've got a respectable set of sample data to test against.


  1. Color spaces are an interesting but rather deep subject of their own. My understanding thus far is that the traditional mapping of RGB values is skewed from how the human eye perceives color. I'm using the LAB colorspace here because I've read it does a better job of capturing what the eye sees.