# Creation of a mask on RGB image

14 views (last 30 days)
Fed on 3 Sep 2020
Answered: DGM on 27 Oct 2022
Hello,
I have applied a mask with irregular contours to a RGB image and then changed the saturation only in the area of the mask.
imshow(Imm);
title('Original Image');
message = sprintf('After you see the cross hairs, \nleft-click and hold to begin drawing.\nSimply lift the mouse button to finish');
uiwait(msgbox(message));
hFH = drawfreehand();
% Create a binary image ("mask") from the ROI object.
figure
imshow(binaryImage)
%Get HSV image from the RGB image
hsvImage = rgb2hsv(Imm);
hueImage = hsvImage(:, :, 1);
saturationImage = hsvImage(:, :, 2);
valueImage = hsvImage(:, :, 3);
% Increase saturation only within the mask area.
satFactor = 1.6;
saturationImage(binaryImage) = saturationImage(binaryImage) * satFactor;
% Recombine
hsvImage = cat(3, hueImage, saturationImage, valueImage);
% Convert back to RGB
rgbImage2 = hsv2rgb(hsvImage);
figure
imshow(rgbImage2);
impixelinfo;
title('Altered RGB Image');
Here the result I got:
Do you know how to obtain a less sharper transition between the mask and the rest of the image in order to get a less artificial effect?
Thank you in advance for your help, I'm not very skilled on Image Processing yet.

J. Alex Lee on 3 Sep 2020
Instead of multiplying pixels in the mask by a constant value, you can mulitply all pixels by an "image" of the saturation multiplier.
So rather than the scalar "1.6", which could as well have been a element-by-element multiplication, your original strategy could have been executed as
[M,N] = size(Imm)
satFactorMat = 1.6*ones(M,N);
satFactorMat(binaryImage) = 1.6;
saturationImage = saturationImage .* satFactorMat;
So now hopefully it is clear you don't really need the mask concept for the operation of altering the image itself, you just might use it to define the satFactorMat "topography", which looks like a mesa.Now you can just smooth it out using something like a smoothing function; you can use imgaussfilt
satFactorMat = imgaussfilt(satFactorMat,6);
You may need to convert everything to doubles first before doing the imgaussfilt and elementwise multiplication, and then convert back to uint8.
Also, note that multiplying is dangerous because you may end up with values outside valid range (>255). So it would be safe to exponentiate (but then you have to normalize your pixel values onto (0,1) first.
hsvImage = double(hsvImage)/255;
% ... everythign in between
% except instead of multiply by satFactorMat, you can do something like
satPowerMat = ones(M,N);
satPowerMat(binaryImage) = 0.3;
satPowerMat = imgaussfilt(satPowerMat,6);
saturationImage = saturationImage .* satPowerMat;
% Recombine
hsvImage = cat(3, hueImage, saturationImage, valueImage);
hsvImage = uint8(hsvImage*255);
Fed on 3 Sep 2020
Thanks again, I will also consider this aspect.

DGM on 27 Oct 2022
While this can be done by directly manipulating S in HSV over a restricted area, there are various ways it could be done. See this example about desaturating part of an image.
In my opinion, it's easier to just handle the composition and adjustment separately unless there are extreme concerns over computational expense. Of course, it's only really easier if you use the appropriate tools.
Say we have an image and mask:
% an image and a logical mask
% the input must not be logical class
mk = imgaussfilt(double(mk),5);
% a copy with increased saturation and altered hue
modpict = imtweak(inpict,'hsv',[-0.2 2 1]);
% composite the output in linear RGB
outpict = replacepixels(modpict,inpict,mk,'linear');
imshow(outpict)
This example uses tools from MIMT, though the link above demonstrates simple composition without it. If you really wanted to do it the hard way:
% an image and a logical mask
% the input must not be logical class
mk = imgaussfilt(double(mk),5);
% a copy with increased saturation and altered hue
[H S V] = imsplit(rgb2hsv(inpict));
H = mod(H-0.2,1);
S = S*2;
modpict = hsv2rgb(cat(3,H,S,V));
% composite the output
FG = rgb2lin(im2double(modpict));
BG = rgb2lin(im2double(inpict));
outpict = im2uint8(lin2rgb(mk.*FG + (1-mk).*BG));
... which is definitely not as convenient anymore. If you're already committed to manually converting the image to HSV and splitting it, you might as well just directly edit S while you're there. Given that MATLAB/IPT don't have any other means to adjust the color, that's kind of the level of inconvenience you're stuck with unless you use third-party tools.