dominant color for an RGB image
32 views (last 30 days)
Show older comments
Hello,
I want to extract the dominant color of an RGB image.
How can I proceed to do that?
23 Comments
DGM
on 10 May 2022
This line
[rMax, gMax, bMax] = ind2sub(size(rgbImage), indexes);
should be
[rMax, gMax, bMax] = ind2sub(size(rgbHist), indexes);
Answers (4)
Sean de Wolski
on 27 Feb 2013
colors = 'RGB';
I = imread('peppers.png');
[~,idx] = max(sum(sum(I,1),2),[],3);
dominant = colors(idx)
0 Comments
Image Analyst
on 26 Feb 2013
How about this:
dominantRedValue = mean2(rgbImage(:, :, 1));
dominantGreenValue = mean2(rgbImage(:, :, 2));
dominantBlueValue = mean2(rgbImage(:, :, 3));
Will that work for you?
11 Comments
Walter Roberson
on 27 Feb 2013
Darned if I can tell. Unless, that is, we start referring to Hue rather than "color"
Image Analyst
on 27 Feb 2013
Edited: Image Analyst
on 23 Nov 2021
Even looking at hue, it's not so easy, as you can see from this screenshot:
That's looking down the value axis from the top. Here's another view from a different perspective:
As you can see whether there is more "green" or "white" pixels depend on where you put the "dividing line" between green and white. It's sort of a continuum so you have to make some kind of criteria. Basically you have to do color classification but to do that you have to decide how many colors you want. Here's one where I chose 48 color classes:
but there are still classes in the "in between" greenish/whitish region and you'll have to decide what to call those. But after that you can find out how many pixels are in each class, then maybe boil it down to two classes and see which has more pixels in it.
mariem farhat
on 27 Feb 2013
5 Comments
Walter Roberson
on 27 Feb 2013
There are so many shades of green there, that I think it plausible that there might be more white than any particular shade of green.
Jan
on 25 Apr 2017
The imageshack link is dead now. Please post the image directly instead of hosting it on any external server.
DGM
on 10 May 2022
While imstats can obviously calculate things like mean, median, or mode, the pagewise mode is usually not what's intended.
rgbpict = imread('peppers.png');
cc = imstats(rgbpict,'mode')
cc =
255 36 0
While there's a lot of red in the image, that tuple does not exist anywhere in the image. Does that matter in your application? It's certainly not close to the most common color either.
From the synopsis:
% 'mode' returns the mode (most common values) per channel
% 'modecolor' calculates the most common color. This differs from 'mode' as
% the most frequent values in individual channels are not necessarily colocated.
% Consider an image which is 40% [1 0 0], 30% [1 1 1] and 30% [0 1 1].
% For this example, 'mode' returns [1 1 1], whereas 'modecolor' returns [1 0 0].
% The latter would be the intuitive answer.
% 'moderange' calculates a selected range of the most common colors in the image.
% Contrast this with 'modecolor' which calculates the singular most common color.
% The range of colors and number of output tuples is specified by parameter 'nmost'.
% This mode supports only I/RGB images.
% 'modefuzzy' calculates the frequency-weighted mean of a selected range of the
% most common colors in the image. The range of colors is specified by parameter
% 'nmost'. This mode supports only I/RGB images.
% The 'modecolor', 'modefuzzy', and 'moderange' options all do color quantization,
% and can therefore alter the color population to some degree. Be wary of using
% the output of these modes for anything of technical importance.
Pay attention to the caveats. The need for quantization is a compromise for speed and memory conservation. Consider how a simple 3D histogramming method might work when the input is a floating-point or uint16 image. The goal of these special 'mode' options is more about visual appearances than exactly matching any one pixel in the image.
Consider the following example. This helps illustrate the different results returned by the various options.
rgbpict = imread('peppers.png');
% get some different image stats
cc = imstats(rgbpict,'mean','median','mode','modecolor','modefuzzy','moderange','nmost',10);
% use those stats to construct a swatch chart for single-output stats
labels = {'mean','median','mode','modecolor','modefuzzy'};
sz = imsize(rgbpict,2);
ntiles = (numel(labels));
tilesz = [round(sz(1)/ntiles) 100];
block1 = zeros([tilesz 3 ntiles],'uint8');
for k = 1:ntiles
thistile = colorpict([tilesz 3],cc(k,:),'uint8'); % colored swatch
thislabel = im2uint8(textim(labels{k},'ibm-iso-16x9')); % text label image
thistile = im2uint8(imstacker({thislabel thistile},'padding',0)); % match geometry
block1(:,:,:,k) = mergedown(thistile,1,'lineardodge'); % blend label and swatch
end
block1 = imtile(block1,[ntiles 1]); % vertically arrange tiles
block1 = imresize(block1,[sz(1) tilesz(2)]); % make sure it's the right size
% create another chart for moderange's multiple outputs
ntiles = (size(cc,1)-ntiles);
tilesz = [round(sz(1)/ntiles) 100];
block2 = zeros([tilesz 3 ntiles],'uint8');
for k = 1:ntiles
thistile = colorpict([tilesz 3],cc(k+4,:),'uint8'); % colored swatch
thislabel = im2uint8(textim(num2str(k),'ibm-iso-16x9')); % text label image
thistile = im2uint8(imstacker({thislabel thistile},'padding',0)); % match geometry
block2(:,:,:,k) = mergedown(thistile,1,'lineardodge'); % blend label and swatch
end
block2 = imtile(block2,[ntiles 1]); % vertically arrange tiles
block2 = imresize(block2,[sz(1) tilesz(2)]); % make sure it's the right size
% show the combined images
imshow([rgbpict block1 block2])
As mentioned before, the results from 'mode' are obviously not the visually-dominant color. In this particular example, 'modecolor' and 'modefuzzy' return similar results. The results from 'moderange' are all very similar. This similarity is not generally the case, so in those cases, you may see 'modefuzzy' results become skewed.
Consider the same code run on other images:
Note how the most frequent colors in the lighthouse image are represented by two different objects/regions. The results from 'modefuzzy' really only make sense if those colors come from one visually distinct region/object, otherwise it won't make sense to take the weighted mean of them. Similar happens with the rubber band picture.
I'm sure that there are some sort of clustering techniques that would work for this task, but I'll leave that to someone who's familiar with it. I just figured I'd throw this out there. For simple things like color-matching components of an image composition, these imstats() options offer a convenience in simple syntax and relatively low resource cost, even if the quantization reduces their usefulness in more technical contexts. While 'modefuzzy' and 'moderange' only work on I/RGB images, most options (including 'modecolor') work on any I/IA/RGB/RGBA/RGBAAA image.
0 Comments
See Also
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!