Color search

On a project, I'm working for I had a task to implement search on images by colors. Existing tags system didn't provide good results as far as image, for example, could have 1% of red but tagged with red color and returned on top of red images search. So the main idea was to build a fast and simple implementation of search by color.

So here is its simplified version of how it was done.

First of all, we have Apache Solr as primary site search engine. Described method doesn't depend strictly on Solr, so you could implement it on various search engines. The main criteria to build results is using sort param. So we need to have some amount of each color filters. In our case, it is possible to filter by 12 colors. All images before colors range processing are cropped to single preset. So we know that all images have similar pixels amount. Next step we used 'Generator Image Color Palette' library by Kalpeh Gamit. This class allows us to get maximum used colors in an image.

$img = new GeneratorImageColorPalette();
$imcolors = $img->getImageColor($image_url, 15, 10);

$image_url - path to an image to extract colors from.
15 - the number of colors to return.
10 - image granularity.
You could play with these numbers and adjust the best accuracy/performance. Now we have an array of most used colors and could analyze them. It’s more comfortable to work with RGB values, so each color is converted to RGB with this function

function html2rgb($color) {
  if ($color[0] == '#') {
    $color = substr($color, 1);
  }
  if (strlen($color) == 6) {
    list($r, $g, $b) = array(
      $color[0].$color[1],
      $color[2].$color[3],
      $color[4].$color[5]
    );
  }
  elseif (strlen($color) == 3) {
    list($r, $g, $b) = array(
      $color[0].$color[0],
      $color[1].$color[1], 
      $color[2].$color[2]
    );
  }
  else {
    return FALSE;
  }
  $r = hexdec($r); $g = hexdec($g); $b = hexdec($b);
  return array($r, $g, $b);
}

So our key

$rgb = html2rgb('#' . $key);

As we already told, there are color filter values on site, a user could search for. Let’s make a function and call it colors_list().

function colors_list() {
  $colors = array(
    "white"   => array(255, 255, 255), 
    "blue"    => array(0, 0, 255), 
    "black"   => array(0, 0, 0), 
    "pink"    => array(255, 0, 128),
    "gray"    => array(164, 164, 164),
    "maroon"  => array(128, 0, 0), 
    "green"   => array(0, 192, 0), 
    "red"     => array(255, 0, 0), 
    "violet"  => array(128, 0, 128), 
    "orange"  => array(255, 128, 0), 
    "yellow"  => array(255, 255, 0), 
    "turquoise_blue" => array(0, 255, 239),
  );
  return $colors;
}

We’ll keep colors list in $colors. But the problem is that we have specific colors, but colors from image could be a various range. To compare and correlate them, here it is a distance formula made as a function:

function distancel2(array $color1, array $color2) {
  return sqrt(pow($color1[0] - $color2[0], 2) +
    pow($color1[1] - $color2[1], 2) +
    pow($color1[2] - $color2[2], 2));
}

So let’s correspond image color to our preset color

foreach ($colors as $name => $value) {
      $distances[$name] = distancel2($value, $rgb);
    }

And choose most close

$mincolor = '';
    $minval = 1000000; // Some big value.
    foreach ($distances as $color_key => $distance) {
      if ($distance < $minval) {
        $minval = $distance;
        $mincolor = $color_key;
      }
    }

Now we have the most close image color amount and it’s corresponding filter name.

$count[$mincolor] = $count[$mincolor] + $color_intencity;

As a result, $count array contains filter colors names and amount of color existing on an image. So you could add this values to search index and sort by specific color.

This is a simlyfied version of color search. Original code also includes some adjustments and improvements to get more accurate and black&white images determining. Feel free to ask any questions in comments.