February 4, 2014

On 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 fast and simple implementation of search by color.

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

First of all we have Apache Solr as primary site search engine. Described method doesn't depends 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 with 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 image.

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

$image_url - path to image to extract colors from.
15 - 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, 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 various range. To compare and correlate them, here it is a distance formula made as 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 image. So you could add this values to search index and sort by specific color.

So complete code will look like this color_search.txt

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

Was this article helpful? Click to rate: 
Average: 4.5 (2 votes)