Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I want to find the major color (the color which appears most often) in a picture and do some analysis later.

For example, if I have this picture:

my picture

What I want to do is find out that gray, red, black, and yellow are major colors in the picture. I thought this could be done by getting a histogram with the X-axis as colors (red, blue, yellow, etc.), and the Y-axis as proportions in the image.

And once I get that histogram, I can retrieve the highest color by comparing the Y-values.

I read some examples of ImageHistogram, ImageLevels and some other color-related functions, but I still don't know how to do this.

Any idea is welcome.

share|improve this question
    
What is the "major color" here? i = 0; Image@Table[{i++/10000, 0, 0}, {h, 100}, {k, 100}] (and why?) –  belisarius May 9 '13 at 3:27
    
I would like to get black and red. Do you mean getting "major color" doesn't make sense? Thanks~ –  Po-Jen Lai May 9 '13 at 3:31
    
There seems to be a DominantColors function. Perhaps that is what you are going for. –  Andy Ross May 9 '13 at 3:32
    
@Ricky In that image each pixel has a different color! –  belisarius May 9 '13 at 3:38
    
@belisarius Oh I understand what you mean. What I want to do is getting information on the object level, but major color doesn't make sense when we see on pixel level, sorry for the vague description. –  Po-Jen Lai May 9 '13 at 3:54

6 Answers 6

up vote 16 down vote accepted

This may be what you are looking for.

img = Import["http://i.imgur.com/Wd9lPRa.jpg"]

enter image description here

Now use DominantColors.

Graphics[{#, Disk[]}] & /@ DominantColors[img, 4]

enter image description here

share|improve this answer
    
This is exactly what I need. Thanks! –  Po-Jen Lai May 9 '13 at 3:54
    
Good answer, but interestingly I couldn't reproduce your results on my computer. Even with the parameter 4 I got four quite different colors from you. I wonder if it's platform or version dependent... –  cormullion May 9 '13 at 8:29
    
Same here, cannot reproduce the colors. Manipulate[Image[{List @@@ DominantColors[img, n]}, ImageSize -> 300], {{n, 2}, 2, 20, 1}] lets you explore the n dominants, ordered based on the size of the clusters they represent says help. So, clusters. –  BoLe May 9 '13 at 9:46
1  
Should not it be Graphics[{#, Disk[]}] & /@ DominantColors[img, 4]? The answer as it is gives error in Mathematica 9.0.1. Anyways colors are completely different also from what you have got here. –  PlatoManiac May 9 '13 at 11:04
1  
@PlatoManiac you are correct. Lets just say I should have checked the version on my kernel. –  Andy Ross May 9 '13 at 12:37

For those without v9, here's another attempt based on FindClusters, but using a different colour space. The idea is to reduce the effect of overall brightness on the "distance" between colours, so that the clustering gives more weight to differences of hue and is less likely to pick out different shades of gray.

newspace[{r_, g_, b_}] := {r - g, b - g, (r + g + b)/10}   
rgbspace[{x_, y_, z_}] := {(2 x - y + 10 z)/3, (-x - y + 10 z)/3, (-x + 2 y + 10 z)/3}

dominants[image_, n_] := Module[{data, cols},
  data = Flatten[ImageData[image], 1];
  data = newspace /@ data;
  cols = Mean /@ FindClusters[data, n];
  RGBColor @@@ rgbspace /@ cols]      

image = Import["Wd9lPRa.jpg"];
Column[{image, GraphicsRow[Graphics[{#, Disk[]}] & /@ dominants[image, 4]]}]

enter image description here

Another example:

image = Import["Water lilies.jpg"] ~ ImageResize ~ 150;
Column[{image, GraphicsRow[Graphics[{#, Disk[]}] & /@ dominants[image, 5]]}]

enter image description here

share|improve this answer

Another potentially useful command of this kind is the CommonestFilter which looks locally about each pixel and chooses the most common value to display. Setting the neighborhood large causes large regions of constant color. For example

img = Import["http://i.imgur.com/Wd9lPRa.jpg"]
CommonestFilter[img, n]

where img is the image from the OPs question yields

enter image description here enter image description here

for n=6 and n=10. Following BoLe's suggestion of using this to preprocess the image, we can now apply DominantColors (as used by Andy) to achieve a reasonable partitioning.

Row[Graphics[{#, Disk[]}]&/@DominantColors[CommonestFilter[img, 10], 6]]

The output of this is:

enter image description here

share|improve this answer
    
Doesn't better my clustering answer, yet it seem a very promising precursor for some other approach. –  BoLe May 9 '13 at 10:41

Try use DominantColors on particular selections instead of the whole. After import select regions you want to analyze and copy that (optionally) multiple selections as a list of images. (New in 9?)

img = Import["http://oaadonline.oxfordlearnersdictionaries.com" <>
   "/media/oaad8/fullsize/f/fru/fruit/fruit_fruit.jpg"]

enter image description here

Paste it and apply dominants to the list.

enter image description here

dominants[selec_List, n_] :=
 Image[{List @@@ DominantColors[#, n]}, ImageSize -> 200] & /@ selec
share|improve this answer

Here's another take. Not that successful though. It might have educational value.

i = Import@"http://i.imgur.com/Wd9lPRa.jpg";

Extract pixel values into a list of length 9k+.

data = Flatten[ImageData[i], 1];
Dimensions@data
{9603, 3}

Show the pixels as 3D points with (x, y, z) for (R, G, B) components.

Table[Graphics3D[todraw,
   Axes -> True,
   AxesLabel -> {"red", "green", "blue"}],
  {todraw, {Point[data],
    MapIndexed[{ColorData[1][First@#2],
       Point[#1]} &, FindClusters[data, 4]]}}] // GraphicsRow

graphics3d

Also shown are points partitioned into 4 clusters of nearest points. Find their centers.

major = Mean /@ FindClusters[data, 4]
{{0.504232, 0.529231, 0.52977}, {0.676402, 0.702754, 
  0.716483}, {0.454949, 0.274621, 0.130194}, {0.0921803, 0.0873291, 
  0.0800836}}

What colors do they represent?

Graphics[MapIndexed[{
    RGBColor @@ #1, Disk[{#2[[1]], 0}, .4]} &, major]]

major colors

share|improve this answer
    
This approach is pretty cool, gives a good intuition as to where the dominant colors are coming from. I wonder if this is how DominantColors works internally? –  Guillochon Jun 7 '13 at 23:09
    
@Guillochon Along this lines. Help notes on the function: The returned colors are ordered based on the size of the clusters they represent. The specifics of clustering I don't know, it could be something cleverer than euclidean distance. –  BoLe Jun 8 '13 at 15:05

You might also enjoy playing with ColorQuantize, which reduces the number of colors used in an image. Here's a BarChart of the results of quantization:

colorquantized = 
  SortBy[
    Tally[
      Flatten[ImageData[ColorQuantize[img, 12, Dithering -> False]], 1]],
   Last];

BarChart[colorquantized[[All, 2]], 
  ChartStyle -> RGBColor /@ colorquantized[[All, 1]]]

bar chart of image colors

I don't think that Yellow is going to make it to the top of this type of list, though...

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.