Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Code for HSV color histogram

1,638 views
Skip to first unread message

Jeevashini

unread,
Dec 13, 2008, 11:34:02 AM12/13/08
to

Hi all,

I have managed to write some simple code for computing HSV histograms for an image.

Please, it's urgent. I would be more than thankful if anyone could check the below code and correct it there is anything wrong.

I = imread('redflower.jpg');
[X,RGBmap] = rgb2ind(I,256);
HSVmap = rgb2hsv(RGBmap);
[count,y] = imhist(X,HSVmap);

Thanks.

Regards,
Vashini

Walter Roberson

unread,
Dec 13, 2008, 12:55:47 PM12/13/08
to
Jeevashini wrote:

> I have managed to write some simple code for computing HSV histograms for an image.

> Please, it's urgent. I would be more than thankful if anyone could check the below code and correct it there is anything wrong.

I have checked the code, but I won't correct it for you. "Urgent" together with the
particular specifications you have given imply an assignment, and it is up to you to
get the assignment right.



> I = imread('redflower.jpg');
> [X,RGBmap] = rgb2ind(I,256);

The second output of rgb2ind (RGBmap) is a colour map. A colour map has one entry
per distinct colour used in the first output (X) -- every entry in RGBmap is different.

> HSVmap = rgb2hsv(RGBmap);

Okay, so there you convert those unique colours into their HSV equivalents

> [count,y] = imhist(X,HSVmap);

help imhist

IMHIST(X,MAP) displays a histogram for the indexed image X. This
histogram shows the distribution of pixel values above a colorbar of the
colormap MAP. The colormap must be at least as long as the largest index
in X. The histogram has one bin for each entry in the colormap.


Unfortunately for you, what you are passing in as the map is the HSV equivalent
of the colormap, not an RGB colormap like the function expects. You will get
a histogram, yes, but the colorbar displayed will be unrecognizable. Matlab
does NOT somehow mark matrices of HSV as being HSV and then know to use HSV
to draw the colorbar: Matlab assumes that when you pass a colormap in to a function
that it is an RGB colormap.

Furthermore, what is being histogrammed are the index values in X, not the HSV
values.

The algorithm you have used will not give you a histogram of the HSV values,
and in particular, it doesn't even come close to giving you a histogram of the
HSV values with 16 bins for H, and 4 bins each for V.

Hint: if H is between 0 and 1, then what happens if you multiply it by 16?

--
.signature note: I am now avoiding replying to unclear or ambiguous postings.
Please review questions before posting them. Be specific. Use examples of what you mean,
of what you don't mean. Specify boundary conditions, and data classes and value
relationships -- what if we scrambled your data or used -Inf, NaN, or complex(rand,rand)?

Jeevashini

unread,
Dec 13, 2008, 2:13:02 PM12/13/08
to
Walter Roberson <robe...@hushmail.com> wrote in message <nGS0l.1676$iY3....@newsfe14.iad>...

Hello Sir,

Thanks for all the explanation and hints you gave.

My question is in no way related to any assignment which I should submit. I am doing a project on Image Classification. And I needed to check on the code urgently for the project whether I was going on the right track as I had planned to finish it before starting on some other work with deadlines.

I had some idea on extracting the RGB histograms for an image :

I = imread(imagename);
rHist = imhist(I(:,:,1), 256);
gHist = imhist(I(:,:,2), 256);
bHist = imhist(I(:,:,3), 256);

But I wondered whether I could do the same for HSV color space.

I will try to think on the hints you gave to get it done. Meanwhile if you have any documents or sites where I could read about a way of doing it, it would be really great.

Thanks.

Regards,
Vashini


Walter Roberson

unread,
Dec 13, 2008, 11:42:17 PM12/13/08
to
Jeevashini wrote:

> I had some idea on extracting the RGB histograms for an image :

> I = imread(imagename);
> rHist = imhist(I(:,:,1), 256);
> gHist = imhist(I(:,:,2), 256);
> bHist = imhist(I(:,:,3), 256);

> But I wondered whether I could do the same for HSV color space.

What would happen if you were to use:

I = rgb2hsv(imread(imagename));

followed by those three calls?

By the way, I suggest you investigate hist(), not just imhist()

Jeevashini

unread,
Dec 14, 2008, 3:44:02 AM12/14/08
to

> What would happen if you were to use:
>
> I = rgb2hsv(imread(imagename));
>
> followed by those three calls?
>
> By the way, I suggest you investigate hist(), not just imhist()

How about the following code:

I = rgb2hsv(imread(imagename));
H = I(:,:,1) ----- the HUE plane
S = I(:,:,2) ----- the SATURATION plane
V = I(:,:,3) ----- the VALUE plane

hHist = imhist(H, 16);
sHist = imhist(S, 4);
vHist = imhist(V, 4);

OR if using the 'histc' function :

[M,N,ttt] = size(RGB);

for (i=1:M)
hHist(i,:) = histc(H(i,:), [0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0]);
end

What this does is : for each row in the matrix H, the histogram for the values from
0 .0 to 1.0 is taken. Thus hHist would be a histogram matrix of size Mx11. We can add the histogram counts in each column of hHist to get the total count of each of the values from 0.0 to 1.0 . For example: adding the count in first column of hHist would give the total histogram count for the value 0.0 in the H matrix.

Please let me know if this right or not.

Vashini

Jeevashini

unread,
Dec 14, 2008, 4:36:02 AM12/14/08
to

> What would happen if you were to use:
>
> I = rgb2hsv(imread(imagename));
>
> followed by those three calls?
>
> By the way, I suggest you investigate hist(), not just imhist()

I just got another idea which I hopefully think would be better than the more complicated one I posted earlier just now. I have managed to use the 'hist' function as you suggested.

I = rgb2hsv(imread(imagename));
H = I(:,:,1);
S = I(:,:,2);
V = I(:,:,3);

hHist = hist(H(:),16);
sHist = hist(S(:),4);
vHist = hist(V(:),4);

Please do let me know if the logic is right.

Thanks.

Regards,
Vashini

Jeevashini

unread,
Dec 14, 2008, 7:17:02 AM12/14/08
to

Please could anyone check and correct me with the above code.

Vashini

Walter Roberson

unread,
Dec 14, 2008, 2:15:47 PM12/14/08
to
Jeevashini wrote:

> I just got another idea which I hopefully think would be better than the more complicated one I posted earlier just now. I have managed to use the 'hist' function as you suggested.

> I = rgb2hsv(imread(imagename));
> H = I(:,:,1);
> S = I(:,:,2);
> V = I(:,:,3);

> hHist = hist(H(:),16);
> sHist = hist(S(:),4);
> vHist = hist(V(:),4);

You have produced a total of 16 + 4 + 4 = 24 bins in your histogram. Your original problem
statement required you to produce 16 * 4 * 4 = 256 bins.

Jeevashini

unread,
Dec 14, 2008, 2:33:01 PM12/14/08
to

> You have produced a total of 16 + 4 + 4 = 24 bins in your histogram. Your original problem
> statement required you to produce 16 * 4 * 4 = 256 bins.
>
> --
> .signature note: I am now avoiding replying to unclear or ambiguous postings.
> Please review questions before posting them. Be specific. Use examples of what you mean,
> of what you don't mean. Specify boundary conditions, and data classes and value
> relationships -- what if we scrambled your data or used -Inf, NaN, or complex(rand,rand)?

I hope the above code is at least right if only 24 bins are going to be used.

Yes. I considered making 256 bins for the histogram to feed into the neural network for classification. But I still couldn't come up with the logic of doing this besides writing the code.

It would be great if you could give some hints about how to proceed with this.

Thanks.

Vashini

Walter Roberson

unread,
Dec 14, 2008, 5:57:44 PM12/14/08
to
Jeevashini wrote:

> Yes. I considered making 256 bins for the histogram to feed into the neural network
> for classification. But I still couldn't come up with the logic of doing this besides
> writing the code.

What code did you come up with?



> It would be great if you could give some hints about how to proceed with this.

Quoting from my original reply to you:

>>>> Hint: if H is between 0 and 1, then what happens if you multiply it by 16?

The hardest part of all of this is adjusting for the fact that H and S and V can
range from -exactly- 0 to -exactly- 1. If one of those two end-points could be
excluded, or treated as belonging to the adjacent case, then the mathematics
of getting the right number of bins becomes fairly easy.

Jeevashini

unread,
Dec 17, 2008, 12:44:03 PM12/17/08
to

> >>>> Hint: if H is between 0 and 1, then what happens if you multiply it by 16?
>
> The hardest part of all of this is adjusting for the fact that H and S and V can
> range from -exactly- 0 to -exactly- 1. If one of those two end-points could be
> excluded, or treated as belonging to the adjacent case, then the mathematics
> of getting the right number of bins becomes fairly easy.

I have written some new code for deriving the HSV histograms with 256 bins as per my initial requirement. Let me know if it is right.

imn=imread('lane28rgbwc.bmp');
imhsv=rgb2hsv(imn);
H=imhsv(:,:,1);
S=imhsv(:,:,2);
V=imhsv(:,:,3);
maxh=max(H(:));
maxs=max(S(:));
maxv=max(V(:));
steph=maxh/16;
steps=maxs/4;
stepv=maxv/4;
%Hhsv contains hsv histogram with 256 bins 16 for H 4 for S and 4 for V
k=1;
for starth=0:15
for starts=0:3
for startv=0:3
Hhsv(k)=0;
for i=1:size(H,1)
for j=1:size(H,2)
if( starth*steph<=H(i,j)<(starth+1)*steph && starts*steps<=S(i,j)
<(starts+1)*steps && startv*stepv<=V(i,j)<(startv+1)*stepv )
Hhsv(k)=Hhsv(k)+1;
end
end
end

k=k+1;
end
end
end

Hhsv gives the final HSV histogram of 256 bins.

Walter Roberson

unread,
Dec 17, 2008, 2:51:26 PM12/17/08
to
Jeevashini wrote:

> if( starth*steph<=H(i,j)<(starth+1)*steph && starts*steps<=S(i,j)
> <(starts+1)*steps && startv*stepv<=V(i,j)<(startv+1)*stepv )

starth*steph<=H(i,j) results in a value of 0 (false) or 1 (true).
You then check to see whether that 0 or 1 is less than (starth+1)*steph.
That will rarely be true if starth*steph<=H(i,j) was true (1) but will
almost always be true if the comparison yielded false (0).

Jeevashini

unread,
Dec 18, 2008, 2:54:03 AM12/18/08
to

>
> > if( starth*steph<=H(i,j)<(starth+1)*steph && starts*steps<=S(i,j)
> > <(starts+1)*steps && startv*stepv<=V(i,j)<(startv+1)*stepv )
>
> starth*steph<=H(i,j) results in a value of 0 (false) or 1 (true).
> You then check to see whether that 0 or 1 is less than (starth+1)*steph.
> That will rarely be true if starth*steph<=H(i,j) was true (1) but will
> almost always be true if the comparison yielded false (0).

I don't understand what you said.

We are going to check if the Hue value of the first pixel which for example has a value 0.4796 lies between 0 and 0.0624 (this range is the first bin for HUE)

starth*steph evaluates to 0
(starth+1)*steph evaluates to 0.0624

Since 0.4796 is greater than or equal to 0 and is less than 0.0624, the expression
starth*steph<=H(i,j)<(starth+1)*steph evaluates to true.

Then the next condition in the 'if' statement is considered in a similar way.

If all three conditions evaluates to True, then the histogram count for that bin increases by 1.


Walter Roberson

unread,
Dec 18, 2008, 9:52:01 AM12/18/08
to
Jeevashini wrote:
>>> if( starth*steph<=H(i,j)<(starth+1)*steph && starts*steps<=S(i,j)
>>> <(starts+1)*steps && startv*stepv<=V(i,j)<(startv+1)*stepv )

>> starth*steph<=H(i,j) results in a value of 0 (false) or 1 (true).
>> You then check to see whether that 0 or 1 is less than (starth+1)*steph.
>> That will rarely be true if starth*steph<=H(i,j) was true (1) but will
>> almost always be true if the comparison yielded false (0).

> I don't understand what you said.

I described how matlab will understand your program, which is different than how you
-think- matlab will understand your program.



> We are going to check if the Hue value of the first pixel which for example has a value
> 0.4796 lies between 0 and 0.0624 (this range is the first bin for HUE)

That is acceptable as a statement of -intent- for the code, but not as a statement
of what the code you gave really does.



> starth*steph evaluates to 0
> (starth+1)*steph evaluates to 0.0624

> Since 0.4796 is greater than or equal to 0 and is less than 0.0624, the expression
> starth*steph<=H(i,j)<(starth+1)*steph evaluates to true.

Incorrect. Matlab does not have a range comparison operation.

if A < B < C
does *not* mean "if B is betweeen A and C". Instead it means
if (A < B) < C
The first part (A < B) returns a logical value (0 or 1) and that logical value is then
compared to C.

To do a range test you need to use

if A < B && B < C


You have another problem: you will lose any H, S, or V value that is -exactly- 1.0
For simplicity of the examination, consider the 1 x 1 image whose RGB is [1 0 eps].
In your code, this would become a 1 x 1 array H of value 1, a 1 x 1 array S
of value 1, and a 1 x 1 array V of value 1. Now follow your code along
to the combination starth = 15, starts = 3, startv = 3, i = 1, j = 1
At that combination you are testing

(15*(1/16) <= 1 && 1 < (15+1)*(1/16)) &&
(3*(1/4) <= 1 && 1 < (3+1)*(1/4)) &&
(3*(1/4) <= 1 && 1 < (3+1)*(1/4))

which is testing

(15/16 <= 1 && 1 < 16/16) &&
(3/4 <= 1 && 1 < 4/4) &&
(3/4 <= 1 && 1 < 4/4)

The first part of each test succeeds because the fractions are less than 1, but the
second part of each test fails, because 1 is not LESS THAN 1: 1 is EQUAL TO 1.
And since you never test with starth of 16 or starts of 4 or startv of 4 you never
try the combination

(16*(1/16) <= 1 && 1 < (16+1)*(1/16)) &&
(4*(1/4) <= 1 && 1 < (4+1)*(1/4)) &&
(4*(1/4) <= 1 && 1 < (4+1)*(1/4))

which would be

(16/16 <= 1 && 1 < 17/16) &&
(4/4 <= 1 && 1 < 5/4) &&
(4/4 <= 1 && 1 < 5/4)

which would be true (in the absence of round-off error, which -is- a problem in
your code.)

However, the cure is -not- to run your loops 0:16 and 0:4 and 0:4 respectively
in order to catch those H or S or V that are exactly 1: if you do that, then you
will get 17 * 5 * 5 = 425 bins instead of 256.

I pointed this issue out to you before in my comment that,

"The hardest part of all of this is adjusting for the fact that H and S and V can
range from -exactly- 0 to -exactly- 1. If one of those two end-points could be
excluded, or treated as belonging to the adjacent case, then the mathematics
of getting the right number of bins becomes fairly easy."


Your code can be completely replaced with a pretty simple fully vectorized function
if you pay attention to the hint I have given you several times,

"Hint: if H is between 0 and 1, then what happens if you multiply it by 16?"

though it does get a little more complicated in order to handle the end-point
problem smoothly.


What-ever code you come up with, you should "walk through" manually, and ask the
questions, "What happens if the H is -exactly- 0? If the H is a hair less than 1/16 ?
If the H is -exactly- 1/16? If the H is a hair more than 1/16?" and so on up to
"If the H is a hair less than 1? If the H is -exactly- 1?" And count the number of different
outcomes you come up with: if you do not come out with precisely 16 different outcomes
then your binning is not working right.

Walter Roberson

unread,
Dec 18, 2008, 3:48:28 PM12/18/08
to
Walter Roberson wrote:

> Your code can be completely replaced with a pretty simple fully
> vectorized function if you pay attention to the hint I have given you several times,

This has gone on long enough, I don't have time to keep giving hints.

l = H(:); l0 = S(:); l00 = V(:);
o = [16 4 4]; O = o*(1-eps);
lOO = histc(prod(o(2:end))*floor(l*O(1)) + prod(o(3:end))*floor(l0*O(2)) + ...
prod(o(4:end))*floor(l00*O(3)),0:prod(o)-1);
bar(0:prod(o)-1,lOO); hold on; plot(abs(fft(lOO)));

Copy-and-paste recommended for testing purposes. The code is designed to stand
out to any marker, so I recommend analyzing what it does and rewriting it.

Jeevashini

unread,
Dec 18, 2008, 11:15:08 PM12/18/08
to

> This has gone on long enough, I don't have time to keep giving hints.
>
> l = H(:); l0 = S(:); l00 = V(:);
> o = [16 4 4]; O = o*(1-eps);
> lOO = histc(prod(o(2:end))*floor(l*O(1)) + prod(o(3:end))*floor(l0*O(2)) + ...
> prod(o(4:end))*floor(l00*O(3)),0:prod(o)-1);
> bar(0:prod(o)-1,lOO); hold on; plot(abs(fft(lOO)));
>
> Copy-and-paste recommended for testing purposes. The code is designed to stand
> out to any marker, so I recommend analyzing what it does and rewriting it.

Thanks for taking all the time for replying to my threads. I am really sorry for the extending this topic all the way. I was determined to make it worth. I kept thinking about the hint you gave. But I always get stuck somewhere in the middle not being able to proceed further. Hence, I wrote the code I posted above which I found out later after you pointed out that it does function incorrectly or inaccurately.

Thanks anyway for the code. I will analyse the code and try to write it again in my own way. I hope I could understand it.

Vashini

Jeevashini

unread,
Dec 22, 2008, 7:45:06 AM12/22/08
to

> > l = H(:); l0 = S(:); l00 = V(:);
> > o = [16 4 4]; O = o*(1-eps);
> > lOO = histc(prod(o(2:end))*floor(l*O(1)) + prod(o(3:end))*floor(l0*O(2)) + ...
> > prod(o(4:end))*floor(l00*O(3)),0:prod(o)-1);
> > bar(0:prod(o)-1,lOO); hold on; plot(abs(fft(lOO)));

I cannot understand what the 'eps' function does in spite of reading about the function in the 'help doc'.

Also I cannot understand how the histogram is derived in the line :

lOO = histc(prod(o(2:end))*floor(l*O(1)) + prod(o(3:end))*floor(l0*O(2)) + ...
prod(o(4:end))*floor(l00*O(3)),0:prod(o)-1);

Why do we have to add the product of 'prod' and 'floor' values of one color plane to the product of 'prod' and 'floor' values of the other two planes.

Also, why do we have to use the prod function from 2 to 4?(This means the values 16, 4 and 1 are used for each of the planes)

I know it would be troublesome and not practical to explain the logic behind the whole code, but I would be thankful if you could shed some light into the logic behind the code.

I have another idea which I am not quite sure whether it's is right :

For example if we are to divide the S and V values into 4 bins each, then why don't we use ranges like this (ignoring the problem of exact end point ranges)

0 <= S <= 0.25
0.26 <= S <= 0.51
0.52 <= S <= 0.77
0.78 <= S <= 1.03

Anyway the values are going to be between 0 and 1, so even if we use ranges greater than 1, does it affect the histogram count?

Walter Roberson

unread,
Dec 23, 2008, 10:40:08 AM12/23/08
to
Jeevashini wrote:
>>> l = H(:); l0 = S(:); l00 = V(:);
>>> o = [16 4 4]; O = o*(1-eps);
>>> lOO = histc(prod(o(2:end))*floor(l*O(1)) + prod(o(3:end))*floor(l0*O(2)) + ...
>>> prod(o(4:end))*floor(l00*O(3)),0:prod(o)-1);
>>> bar(0:prod(o)-1,lOO); hold on; plot(abs(fft(lOO)));

> I cannot understand what the 'eps' function does in spite of reading about the function
> in the 'help doc'.

Repeating myself:

>> What-ever code you come up with, you should "walk through" manually, and ask the
>> questions, "What happens if the H is -exactly- 0? If the H is a hair less than 1/16 ?
>> If the H is -exactly- 1/16? If the H is a hair more than 1/16?" and so on up to
>> "If the H is a hair less than 1? If the H is -exactly- 1?" And count the number of different
>> outcomes you come up with: if you do not come out with precisely 16 different outcomes
>> then your binning is not working right.

If you had done that walk-through, you would understand the role of the (1-eps) in
the calculation, provided that you can figure out what 1 - eps is at all.

>> format hex
>> 1

ans =

3ff0000000000000

>> 1 + eps

ans =

3ff0000000000001

So 1 + eps is the next representable binary floating point number after 1, and
conversely, 1 - eps is a representable binary floating point number that is
just slightly less than 1.


> Also I cannot understand how the histogram is derived in the line :
>
> lOO = histc(prod(o(2:end))*floor(l*O(1)) + prod(o(3:end))*floor(l0*O(2)) + ...
> prod(o(4:end))*floor(l00*O(3)),0:prod(o)-1);

> Why do we have to add the product of 'prod' and 'floor' values of one color plane to the
> product of 'prod' and 'floor' values of the other two planes.
> Also, why do we have to use the prod function from 2 to 4?(This means the values 16,
> 4 and 1 are used for each of the planes)

No good reason. I just felt like making code that was compact, efficient, correct,
generalized if the number of bins were happen to change, and simple to understand
by anyone who has gone through grade five arithmetic on number bases. You should feel
free to replace it with better code. Remember, I didn't say that my code was the best
code, just that it had been designed to stand out to markers.


> I have another idea which I am not quite sure whether it's is right :

> For example if we are to divide the S and V values into 4 bins each, then why don't we use
> ranges like this (ignoring the problem of exact end point ranges)

> 0 <= S <= 0.25
> 0.26 <= S <= 0.51
> 0.52 <= S <= 0.77
> 0.78 <= S <= 1.03

> Anyway the values are going to be between 0 and 1, so even if we use ranges greater than 1,
> does it affect the histogram count?

If you were to histogram (1-S) with the above code, and then to reverse the order of the
counts, would you get the same answer as when you histogrammed S itself?

0 new messages