# How to find major color in a picture?

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:

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.

-
What is the "major color" here? i = 0; Image@Table[{i++/10000, 0, 0}, {h, 100}, {k, 100}] (and why?) – Dr. 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! – Dr. 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

This may be what you are looking for.

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


Now use DominantColors.

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


-
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
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
@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]]}]


Another example:

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


-

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

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:

-
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" <>


Paste it and apply dominants to the list.

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

-

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


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]]


-
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]]]


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

-