# How to set the hue and saturation value in hsv color model.

23 views (last 30 days)

Show older comments

##### 3 Comments

### Answers (1)

DGM
on 19 Apr 2022

I doubt this question needs to be solved anymore, but it brings up an issue that's easy to miss.

In general, when someone asks "how to I constrain image values to a given range, there are a couple obvious answers. You can either truncate the values, or you can rescale them to fit. What you choose depends on your goals. Rescaling is typically going to produce results which have better retention of local contrast and are less visually objectionable. So let's try doing both.

First, let's truncate H and S.

A = imread('peppers.png');

% convert and split

Ahsv = rgb2hsv(A);

[H S V] = imsplit(Ahsv);

% truncate S

Snew = imclamp(S,[100 255]/255);

figure

subplot(2,1,1); imhist(S) % show histogram before

subplot(2,1,2); imhist(Snew) % show histogram after

% blindly truncate H

Hnew = imclamp(H,[10 40]/255);

figure

subplot(2,1,1); imhist(H) % show histogram before

subplot(2,1,2); imhist(Hnew) % show histogram after

% reassemble image

B = hsv2rgb(cat(3,Hnew,Snew,V));

% show result

figure

imshow(B)

Then let's rescale H and S.

A = imread('peppers.png');

% convert and split

Ahsv = rgb2hsv(A);

[H S V] = imsplit(Ahsv);

% rescale S

Snew = imadjust(S,[0 1],[100 255]/255);

figure

subplot(2,1,1); imhist(S) % show histogram before

subplot(2,1,2); imhist(Snew) % show histogram after

% blindly rescale H

Hnew = imadjust(H,[0 1],[10 40]/255);

figure

subplot(2,1,1); imhist(H) % show histogram before

subplot(2,1,2); imhist(Hnew) % show histogram after

% reassemble image

B = hsv2rgb(cat(3,Hnew,Snew,V));

% show result

figure

imshow(B)

Well, those both look like garbage. Rescaling or truncating S or V is fairly straightforward, but H is a circular continuum. H = 10 is closer to H = 350 than it is to H = 40. When you move the endpoints of the transfer curve away from [0 1], you're splitting what used to be a continuous space and potentially moving color points away from their neighbors.

In this example, the hue distribution is largely centered around red -- around H = 0. In this particular case, the hue distribution has clear extents. If we recognize this, we can do something strategic:

A = imread('peppers.png');

% convert and split

Ahsv = rgb2hsv(A);

[H S V] = imsplit(Ahsv);

% rescale S

Snew = imadjust(S,[0 1],[100 255]/255);

figure

subplot(2,1,1); imhist(S) % show histogram before

subplot(2,1,2); imhist(Snew) % show histogram after

% rotate H prior to rescaling

Hnew = mod(H+0.5,1);

Hnew = imadjust(Hnew,[0 1],[10 40]/255);

figure

subplot(2,1,1); imhist(H) % show histogram before

subplot(2,1,2); imhist(Hnew) % show histogram after

% reassemble image

B = hsv2rgb(cat(3,Hnew,Snew,V));

% show result

figure

imshow(B)

By rotating H prior to rescaling, the hue distribution doesn't get split and the image remains smooth. Of course, one can easily imagine a colorful image where there is no good place to split the histogram, so this isn't a general solution. In fact, it's such an underspecified problem that one has to question the applicability of any solution.

There are certainly trivial ways to accomplish the goals for any image. Say we simply discard the original H content:

A = imread('peppers.png');

% convert and split

Ahsv = rgb2hsv(A);

[H S V] = imsplit(Ahsv);

% rescale S

Snew = imadjust(S,[0 1],[100 255]/255);

% replace H with an arbitrary field within the specified interval

Hnew = repmat(linspace(10/255,40/255,size(H,1)).',[1 size(H,2)]);

% reassemble image

B = hsv2rgb(cat(3,Hnew,Snew,V));

% show result

figure

imshow(B)

A = imread('peppers.png');

% convert and split

Ahsv = rgb2hsv(A);

[H S V] = imsplit(Ahsv);

% rescale S

Snew = imadjust(S,[0 1],[100 255]/255);

% replace H with a scaled copy of V

Hnew = 10/255 + 30/255*V;

% reassemble image

B = hsv2rgb(cat(3,Hnew,Snew,V));

% show result

figure

imshow(B)

You'll have to decide what the actual requirements are.

##### 2 Comments

DGM
on 20 Jul 2022 at 7:54

That really isn't related to hue manipulation and continuity. That's a segmentation problem that stems from a lack of demonstrable constraints. It might be one thing to extract an apple from one image using static thresholds. It might even work for a number of similar images, but if someone asks "I have this handful of images. How can I pick fixed thresholds that will let me isolate any apple from any image", the answer is that there's no reason to believe that such things are even possible.

The problem might be solved for two images:

A = imread('012-07-L.jpg');

B = imread('023-07-L.jpg');

% just cram both samples into one image

% to demonstrate that the segmentation works on the union of images

AB = imresize([A;B],0.5);

ABhsv = rgb2hsv(AB);

% HSV thresholds

th = [0.70 0.12;

0.00 1.00;

0.00 0.85];

% basic color-based mask generation

th = permute(th,[3 2 1]);

mask = all(ABhsv(:,:,1) >= th(1,1,1) | ABhsv(:,:,1) <= th(1,2,1),3);

mask = all(ABhsv(:,:,2:3) >= th(1,1,2:3) & ABhsv(:,:,2:3) <= th(1,2,2:3),3) & mask;

% remove speckles

minspecksize = 50;

mask = bwareaopen(mask,minspecksize);

mask = ~bwareaopen(~mask,minspecksize);

% show combined mask

imshow(mask)

... but without knowing the full scope of the lighting and tone variations across all the images, there's no way to know if this will work for any images in the dataset other than these two. It's probably good for quite a few, but that's not something that can be known from here.

If static thresholds aren't sufficiently robust for this sort of thing, what is? I don't know. Despite the fact that I gave an example, this really belongs in a new question.

### See Also

### Community Treasure Hunt

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

Start Hunting!