How to count average Hue of all pixels except the black one?

I have this HSV picture i already processed. my question is, how to get the average level of all colorful pixels? i dont want the black pixels being counted. just the pixels with color. any idea how?

 Accepted Answer

Your problem statement is ambiguous; "just the colorful pixels" isn't the same as "non-black pixels". You'll have to decide what you actually want, but I'm going to assume "non-black pixels" for this example.
% read the image
inpict=im2double(imread('image.png'));
% i'm going to assume you don't want the white border either
% since the angles there are likely meaningless
% if that's not the case, just ignore this.
inpict=cropborder(inpict,[NaN NaN NaN NaN]);
% cropborder is in the MIMT (on the File Exchange)
% convert to some polar model of choice.
% i'll use HSV, since i guess you're using it.
hsvpict=rgb2hsv(inpict);
% pick some threshold value according to your needs
% rgb2hsv gives normalized V, so if you use a different model, this might
% need to be adjusted accordingly.
goodpix=hsvpict(:,:,3)>0.001;
% denormalize hue and extract the values of interest
% denormalizing is only needed here since rgb2hsv gives normalized H
% not all conversion tools do that.
goodhues=hsvpict(:,:,1)*360;
goodhues=goodhues(goodpix);
% average of angles isn't the simple arithmetic mean
averagehue=atan2d(sum(sind(goodhues)),sum(cosd(goodhues)))
That's the general idea. Develop a logical mask to extract the desired pixels from the hue map, and average them.
If instead you prefer to extract "just the colorful pixels", then that would also exclude white and gray pixels. Thresholding chroma may be more appropriate than saturation, so a different model might be simpler to use. If it's decided that thresholding saturation would suffice, HSV may still be one of the worst models to use due to the gross assymetry of its saturation space. Then again, I don't know what suits your technical requirements.

6 Comments

Building on DGM's answer, if you want to get a mask of only those pixels with a certain level of saturation, you could do
saturationImage = hsvPict(:, :, 2) > 0.25; % or whatever.
That would give a map of pixels that are fairly vivid. You could AND that with another mask of where the value is more than some value.
You might want to experiment around with the Color Thresholder app on the Apps tab of the tool ribbon. Load your image from disk and use HSV color space and play around with the thresholds to get a mask. Then export the code to a function and use the mask as an index into your hue image.
@DGM my apologize for the ambigiuous statement, and yes you are right. what i want is the non-black pixels. anyway thanks for the idea, ill try some code to figure it out.
from ur answer i can say that :
averagehue=atan2d(sum(sind(goodhues)),sum(cosd(goodhues)))
this piece of code is the function i need to gather the average hue. am i right? please correct me if im wrong
@Image Analyst thats another good tip for me, thanks!
and another question for you guys. do i really have to adjust the saturation and value to proccess this picture? im sorry for asking some kind of question but im new with this matlab and hsv picture thing and im glad you're all helping :D
Yes. to understand why the simple arithmetic mean of hues won't work, consider a case where your hues are clustered together like so:
H=[340 350 10 20];
A=mean(H)
B=atan2d(sum(sind(H)),sum(cosd(H)))
The arithmetic mean A neglects to consider that the space is circular. A comes out as 180, which is about as far as you can get from the group. On the other hand, B gives the intuitive answer 0.
You don't necessarily need to adjust the saturation/value, but if you want to exclude certain pixels based on their color properties, you would need to derive a corresponding mask. The easiest way to segregate pixels based on color properties is to convert a copy of the image into a color space where the properties of interest are well-separated and can be thresholded. It doesn't necessarily even have to be the same color model used to calculate hue, though for what it's worth, hue isn't shaped the same in all polar color models.
In the example above, I converted to HSV in order to find "non-black" pixels. I know you said you want "non-black", but as an exercise, let's say I had wanted to find "colorful" pixels instead. Let's say that I decide that "colorful" means "high saturation". I might use HSL, since its saturation space is symmetric. The basic idea is still the same. All you need is your hue map and a means to generate a binary mask.
% convert to some polar model of choice.
% i'll use HSL, since its saturation space is symmetric
% and more selective than HSV or HSI
% i'm using rgb2hsl from the MIMT toolbox on the File Exchange
hslpict=rgb2hsl(inpict);
% threshold saturation
% pick some threshold value according to your needs
goodpix=hslpict(:,:,2)>0.01;
% this HSL tool already gives denormalized hue
goodhues=hslpict(:,:,1);
goodhues=goodhues(goodpix);
... But does saturation really describe what we need when we think of "colorful"? Neutral "non-colorful" colors exist on the diagonal of the RGB cube between black and white, and if our goal were to exclude those, we would probably want to be excluding color points near that diagonal. In a polar model, what we would be targeting are colors based on their radius from the central axis. ... but saturation isn't chroma. It's a normalized proxy for chroma. Its convenience is that it's normalized, but it really doesn't describe "colorfulness" as appropriately. It's helpful to understand what the saturation space looks like:
These are surfaces of 50% saturation in HSV, HSI, and HSL. Of particular note is the behavior near the corners. This tells us that near black or white, the meaningfulness of saturation becomes quite questionable. The color tuple [0 0 0] has zero saturation, but [0 0 0.00001] has 100% saturation. It's fair to say that the latter is not meaningfully more colorful than the former.
On the other hand, the locus of constant chroma is (for the purposes of this discussion) essentially cylindrical. It can easily segregate colors near the extreme corners of the RGB cube.
If there are no particular requirements otherwise, I often use polar YPbPr, as it's still simple and fast to calculate.
% convert to some polar model of choice.
% i'm using polar YPbPr
% i'm using rgb2lch from the MIMT toolbox on the File Exchange
lchpict=rgb2lch(inpict,'ypbpr','notruncate');
% threshold chroma
% pick some threshold value according to your needs
goodpix=lchpict(:,:,2)>0.01;
% this LCH tool already gives denormalized hue
goodhues=lchpict(:,:,3);
goodhues=goodhues(goodpix);
Of course, like I think I mentioned, H in HSV/HSL isn't the same as H in HSI or polar YPbPr or other models. IIRC, HSV/HSL is polygonal, whereas HSI and others are smooth. There are also offsets to consider. If you need your hue angles to be in a particular color model, you can still generate your mask using a different color model:
% convert to some polar model of choice.
lchpict=rgb2lch(inpict,'ypbpr','notruncate');
% pick some threshold value according to your needs
goodpix=lchpict(:,:,2)>0.01;
% the mask was generated using LCH, but hue map comes from HSV
hsvpict=rgb2hsv(inpict);
goodhues=hsvpict(:,:,1)*360;
goodhues=goodhues(goodpix);
That's probably enough of an aside to be more confusing than helpful, so I should probably stop. You get the point. Pick a model that can provide an easy means to segregate colors based on the properties that interest you. If all you need to exclude are dark pixels, just do that. If HSV works for your purposes, us it.
Current versions of Matlab probably have conversion tools for most color spaces. There are others available on the File Exchange. The ones I've used in these examples come from here:
If you don't need a programmatic method to extract the "good pixels", consider using immask() from that toolbox. It provides a GUI to do color-based mask generation in various color models, but it's a bit awkward to use.
The Color Thresholder app that Image Analyst mentioned is of similar purpose, though it doesn't (afaik) offer polar operation in anything other than HSV.
@DGM thanks for all the explanation. it take me a long time to understand. my bad.
from what i read from your explanation, u said we cant take average hue level using simple arithmatic like we used to find mean. then, what if i turn back the hsv picture itu rgb version. find the mean of all rgb pixels. except the black pixels of course because i already mask it. then, change the RGB mean into hue? is it fine to do this??
im using this idea because i found some formula from the internet to change RGB into hue.
please answer this one.
You could do that if it suits your requirements. The weakness of either method is when the inputs are complementary. If averaging in RGB, you'll end up with a gray value with (essentially) undefined hue. If averaging angles, the angle becomes ambiguous and the formula I gave will give a garbage answer; after all, what angle is halfway between 0 and 180? Is it 90 or 270? So long as all your colors don't average out to a gray (they don't in this case), you should be fine. If you need speed, it might be faster to do it in RGB.
thanks for the answer bro, you really help me alot!

Sign in to comment.

More Answers (0)

Categories

Find more on Creating, Deleting, and Querying Graphics Objects in Help Center and File Exchange

Asked:

on 27 Mar 2021

Commented:

on 29 Mar 2021

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!