4
votes

I would like to check what colors is present in a image. This will be stored in the database and used for a search form. (red=1, green=1, blue=0, yellow=1, black=1, white=1 etc.)

img = Magick::Image.read('phosto-file.jpg').first
img = img.quantize(10
h = img.color_histogram
pp h
{red=12815, green=18494, blue=15439, opacity=0=>13007,
 red=44662, green=47670, blue=51967, opacity=0=>18254,
 red=17608, green=43331, blue=48321, opacity=0=>11597,
 red=21105, green=25865, blue=39467, opacity=0=>10604,
 red=15125, green=36629, blue=22824, opacity=0=>10223,
 red=52102, green=42405, blue=10063, opacity=0=>12928,
 red=39043, green=28726, blue=40855, opacity=0=>7728,
 red=10410, green=8880, blue=7826, opacity=0=>13795,
 red=25484, green=25337, blue=24235, opacity=0=>7351,
 red=44485, green=12617, blue=11169, opacity=0=>14513}

How do I convert the 10 values to color names? red, green, NOMATCH, yellow, black, white etc. Only need the rough color name - not LimeGreen but Green etc.

Best regards. Asbjørn Morell

3
The ruby code on your example isn't valid: opacity=0=>13007 isn't valid.kikito

3 Answers

1
votes

If you could represent all of the colors you are looking for in the same number format that ImageMagick returns. Then you could compare the RGB values to find which it is closest to.

So for instance if you have a histogram value of (assuming 255 values for each color, YMMV)

{ red => 10, green => 255, blue => 10 }

Then you could compare it to each of

{
  red   => {red => 255, green => 0, blue => 0},
  green => {red => 0, green => 255, blue => 0},
  blue  => {red => 0, green => 0, blue => 255}
}

So if you add up the difference between all of the elements you'll get

{
  red   => 510,
  green =>  20,
  blue  => 510,
}

So you can clearly see that the color is closest to green

UPDATE: Added a solution in Ruby


def compare_color(color_val)
  colors = {
    :red    => [255,0,0],
    :green  => [0,255,0],
    :blue   => [0,0,255]
  }

  difference = {}

  def compare_array(a1,a2)
    total = 0
    a1.each_index do |x|
      total += (a1[x]-a2[x]).abs
    end
    total
  end

  colors.each do |color,hex|
    difference[color] = compare_array(color_val,hex)
  end

  closest = difference.sort{|a,b| a[1]  b[1]}.first                                                                       [closest,difference]
end

p compare_color([10,255,10])
# [[:green, 20], {:red=>510, :green=>20, :blue=>510}]
1
votes

The simple way would be to have a list of RGB values and the corresponding names, and you'd select the closest matching colour (within some acceptable margin of error). For just the basic colours, even a very simple sum of differences in each of the RGB channels could give workable results, although I suspect you will run out of colour names if the data looks like that. You can find a list of colour names on the net, perhaps stripping down one such list might help. (Note that these usually expect a range of 0..255 for the colours, so you'd need to convert down from the wider range in your data.)

A slightly more advanced way could be to convert the RGB values into hue, saturation, and luminance and use those to generate names, e.g. "dark red" when the hue is red, saturation is high enough to not be grey, and luminance is low (but not low enough to be black).

1
votes

You might find this post on my blog interesting. It explains exactly how to solve your problem. I've also released ColorNamer gem that gives you closest named color from RGB value or HTML hash. You can also use any Color object