Fading/shading an image

47 views (last 30 days)
Sara Macchiavello
Sara Macchiavello on 11 Aug 2020
Edited: DGM on 6 Sep 2023
Good evening,
I had to darken half of a RGB image in order to recreate an emianopsy. Here is the code I used:
%Loss of left visus
A = imread('lena .bmp');
[x,y,z]=size(A); %dimensions' estraction RGB image
Y=y/2; % halving y axis
HSV = rgb2hsv(A); %conversion to hsv space
%Process the HSV image. This example decrease the brightness of half image by multiplying the V channel by a scale factor.
[h,s,v] = imsplit(HSV); %split hue, saturation and value channels
vFactor = 0.2; %define the scale factor for brightness
% for cicle darken pixels of the left part of the image
for i=1:x
for j=1:Y
v(i,j) = v(i,j)*vFactor;
end
end
HSV_v = cat(3,h,s,v); %reconstrucion of HSV image
%Convert the processed HSV image back to the RGB color space.
Av = hsv2rgb(HSV_v);
figure
imshow(Av)
title('Left emianopsy');
Here is the resulting image:
The separation between the 2 parts of the image is too sharp and marked, so I'd like to obtain a more faded transition between the dark and the coloured side (like a gradient?). How can I obtain a realistic result? like for example the image below:
Thank you in advance
  1 Comment
hosein Javan
hosein Javan on 11 Aug 2020
the reason why your image is not a garadient, is that you are multiplying one single value factor to the whole half left part of the image rather than multiplying a series of factors that change smoothly according to pixel position.

Sign in to comment.

Accepted Answer

hosein Javan
hosein Javan on 11 Aug 2020
A = imread('lena.bmp'); % read rgb image named 'lena.bmo'
figure(1);imshow(A) % show the original image in figure1
dim = linspace(0,1,512); % create a linear dimming factor across horizontal dimension of the image
dim = repmat(dim,[512 1 3]); % repeat dimming factor for all rows
Adim = uint8(dim.*single(A)); % multiply the dimming factor to the original image and store it in "Adim"
figure(2);imshow(Adim) % show the dim image in figure2
  8 Comments
hosein Javan
hosein Javan on 13 Aug 2020
Ciao! and Prego!. sorry I don't know italian well although I love the language.
sorry for answering too late, I was thinking. since matlab functions such as "roifilt" apply bluring effect on a specific area on an image, we can't simply have a faded effect at the boundaries. although I have an idea. we can define the blurring effect of our own in such a way we can set the intensity on pixels of interest by a arbitrary function. I'm going to think about it. Can you tell me how much time you have to fulfill this project so I can plan for it? because I'm not sure I can solve the problem so soon.
Sara Macchiavello
Sara Macchiavello on 2 Sep 2020
Goodmorning, I'm sorry to bother you but you were very helpful and kind so I'd like to ask you another question regarding the further developments of my project.
I'd like to create some irregular regions in a RGB image with an effect similar to contour plots. I have to work on these regions for example modifying contrast, saturation or luminance into every region created. As a consequence I think that the drawfreehand and roipoly commands are not suited for my purpose because I saw that they create a mask on which I can't apply transformations named above. Do you know if is there the possibility to obtain this effect?
Thank you

Sign in to comment.

More Answers (1)

DGM
DGM on 21 May 2022
Edited: DGM on 6 Oct 2022
A 'multiply' blend is one of the simple and fundamental kinds of image blending. If you have appropriate images to begin with and you pay attention to your image class and data scaling, you should be fine.
I've posted plenty of other reference answers about doing similar things with standard tools, but I don't feel like it tonight. MATLAB does not have any practical tools for image blending or composition, so I think it's kind of unreasonable to reinvent a missing wheel every single time. For these examples, I'm going to use tools from MIMT, which is available on the File Exchange.
As in any image manipulation environment, MIMT imblend() can simply blend (and composite) two images. You don't have to be stuck with ultra-simple things like 'multiply' and 'addition' blends, and you don't have to guess at the behavior of closed-source software which no longer exists or debug potentially erroneous formulae found on an abandoned blog somewhere. I already did that.
% background image (RGB, uint8)
BG = imread('lena.jpg');
% create foreground image (grayscale, uint8)
s = imsize(BG);
FG = lingrad(s(1:2),[0.2 0.25; 0.8 0.75],[0; 255],'cosine');
% show the images
montage({FG,BG})
% blend the images
%outpict = imblend(FG,BG,1,'multiply');
%outpict = imblend(FG,BG,1,'colorburn',0.5);
%outpict = imblend(FG,BG,1,'linearburn',0.5);
outpict = imblend(FG,BG,1,'suauburn');
multiply color burn
linear burn suau burn
While imblend() is compared to Photoshop or GIMP in that it supports image blending, it's dissimilar in that it supports more options than any image manipulation suite does. Most of the modes are adjustable in ways which are convenient for their typical use. In the above example, the lineardodge and colordodge blends are done with a parameter of 0.5, resulting in subtle and rich results unobtainable through scalar opacity adjustment.
Admittedly, my goal here isn't to create anything that really looks good. Slapping a black gradient on lena is just a tangent on the replication of OP's example. Anyone who is familiar with blending images in Photoshop, etc should be able to plan the composition they desire. Having a better hammer doesn't help if you don't know where to put the nails.
So let's try another. MIMT also has tools for creating simple two-point and multipoint gradients. Instead of a linear grayscale gradient, let's use a colored radial gradient. We'll use the same sort of NRL-leveraged blending with darkening modes to do a sort of goofy mood vignetting.
% background image (RGB, uint8)
BG = imread('lena.jpg');
% create foreground image (RGB, uint8)
easew = 0.5; % normalized WRT image width
s = imsize(BG);
FG = radgrad(s(1:3),[0.5 0.5],0.5,[255 255 255; 100 50 255],'ease');
% show the images
montage({FG,BG})
% blend the images
%outpict = imblend(FG,BG,1,'multiply');
%outpict = imblend(FG,BG,1,'colorburn',0.8);
%outpict = imblend(FG,BG,1,'linearburn',0.8);
outpict = imblend(FG,BG,1,'suauburn');
multiply color burn
linear burn
I suppose that's a bit better than black. Again, these blends are adjustable. It takes more than a handful of pictures to explain what the difference is between 'multiply' and the other modes. If all you need to do is to something like this, the details probably don't matter much. The synopsis for imblend() has extensive description of the behaviors, and most modes have their technical properties documented here.
As for the last questions about blurring an image region -- this is a simple task of linear image composition. You could combine images using a logical mask, but the transition will always have ugly jagged edges. You want to do linear composition.
Again, much like the black gradient overlay, you can't get a smooth transition if you don't start with a smooth mask. Whether it's a circle or a polygon, you'll need to come up with a way to make it smooth. If you start with a logical image and try to blur it, make sure to cast it as something other than logical before you blur it.
Don't use roifilt() if appearances are important. Internally, roifilt() is very simple in concept. Much like the code below, it filters a copy of the image and then composes the two copies of that image. Instead of doing that to the whole image, it does it on the rectangular region which circumscribes the mask ROI. It doesn't do any sort of fancy mask-aware weighting or window traversal to process the actual nonrectangular mask region. It's useful for its efficiency when the filtered region is very small in comparison to the overall image, but it uses logical composition internally, so the results will always have jagged edges, even if the mask is smooth.
While roifilt2() is limited like that, MIMT has a similar tool called roifilter() that can support linear masks, color images, and blobwise operations. If the mask region is small compared to the image, there may be a speed advantage to using it. In this example, a soft circular mask is simply generated by applying a nonlinear contrast curve to a radial gradient with a linear ease curve. A blur operation is confined to the region defined by the mask.
% background image (RGB, uint8)
BG = imread('lena.jpg');
% create soft mask
mask = radgrad(imsize(BG,2),[0.5 0.5],0.27,[255; 0]); % linear radial gradient
mask = imlnc(mask,'independent','in',[0 0.5],'k',3); % adjust contrast
% use roifilter() with a kernel size spec
% this specifies the diameter of a gaussian kernel with sigma = 0.15*D
outpict = roifilter(BG,mask,133,'linear'); % sigma = ~20px
% use roifilter() by supplying a filter kernel instead
fk = fspecial('gaussian',133,20);
outpict = roifilter(BG,mask,fk,'linear');
If the mask area isn't significantly smaller than the image or there's other needs, this can always be done by basic composition as before. While imblend() can be used for both blending and compositing, replacepixels() is often more convenient when all that's needed is compositing (and when the mask is unattached). It's definitely more convenient than doing all the class handling and multiplication the long way every time.
% background image (RGB, uint8)
BG = imread('lena.jpg');
% create foreground image (RGB, uint8)
FG = imgaussfilt(BG,20);
% create soft mask
mask = radgrad(imsize(FG,2),[0.5 0.5],0.27,[255; 0]); % linear radial gradient
mask = imlnc(mask,'independent','in',[0 0.5],'k',3); % adjust contrast
% show the images and mask
montage({FG,BG,mask})
% compose the images in linear RGB
outpict = replacepixels(FG,BG,mask,'linear');
While something like this is easily handled by composition in practice, be aware that transitioning a blur by composition isn't the same thing as using a variable-kernel blurring operation. See this answer:
Consider also the following answers to similar questions regarding basic image composition:
  5 Comments
dinesh bharathi
dinesh bharathi on 23 Sep 2022
Thanks for this @DGM Am yet to try this out.
Meanwhile apart from the linear and radial, is it also possible to have complex shapes? like uneven rectangle or polygon or something similar to that?
DGM
DGM on 24 Sep 2022
Edited: DGM on 6 Sep 2023
There isn't really a MIMT tool specifically for arbitrary gradients. There are some options though. Consider the following example:
% say you have a mask that defines the shape
% this is a single-channel antialiased image
mask = imread('monojagblob.png');
% invert the mask, then calculate the distance transform, normalize
% this creates a unit-scale map from the object boundary to its interior
D = simnorm(bwdist(iminv(mask)));
Bear in mind that as this example exploits the distance transform, the ease curve of the gradient will be linear. It's possible to adjust that by manipulating the contrast of D.
% the contrast parameter used by imlnc() is a smooth symmetric curve
D = imlnc(D,'independent','k',1.5); % k is a contrast factor
If you want an actual cosine ease curve instead of some arbitrary adjustable thing, that should be easy enough to do mathematically given that D is unit-scale and floating point already.
D = 1-(cos(D*pi)+1)/2; % strictly cosine
If something other than a monochrome gradient is desired, then the colored gradient can be constructed from solid fields using the distance map as a mask.
% note that replacepixels needs BG to be an image
% but FG can just be a color tuple
% so we only actually need to explicitly create
% one of the two solid color images
CT = uint8([282 183 35; 100 0 80]); % a two-color color table
outpict = replacepixels(CT(1,:),CT(2,:),D);
% use the original mask to constrain the gradient extents if desired
outpict = replacepixels(0,outpict,iminv(mask));
While the composition approach above allows the distance map to be converted into a 2-color gradient, an alternative approach might be to use colormapping tools. That can allow however many colors/breakpoints you can cram into the colormap.
% apply a full colormap instead of a 2-point gradient
numcolors = 256;
CT = ccmap(numcolors); % any colormap of appropriate length
% a non-MIMT approach:
%D = round(D*(numcolors-1) + 1); % for FP classes, idx = 1 corresponds to the first color
%outpict = ind2rgb(D,CT);
% a MIMT approach:
outpict = gray2pcolor(D,CT); % D doesn't even need to be normalized here
% same as before; optional
outpict = replacepixels(0,outpict,iminv(mask));

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!