how to blend an image that is a non-rectangular mask with a background image?

5 views (last 30 days)
Okay, I'm stumped.
I have a background image and I want to put a circular mask image on top of it, blended together 50-50 for everything within the circle. I want to stick with images and not use figures so that I can view the results with imagesc(image).
If pic1 is the full image that is cropped into the circle, and pC is a black circle on a white background with dimensions bCx, bCy, I use this to add in the image I want.
pzzc = imadd(pic1(bCx,bCy,:),pC);
I now have a circle with the original image in it and a white background. So far so good.
I now want to combine that image with the background image, such as this.
pzzz = imfuse(pzzz, pzzc,'blend');
The problem is that this doesn't work, as I can't get rid of the square bounding box around the circle image, since it's a mean of the 2 images, white and background.
immultiply doesn't work either. With this alternate approach:
pzz = immultiply(uint16(pzzz(bCx,bCy,:)), uint16(pzzc)); % IMAGE AND BACKGROUND
pzzz(bCx,bCy,:) = uint8(pzz);
pzz has the circle correct but is unblended, and the masked part of pzzz just comes out white.
If I have to I can live with the unblended image, but I don't understand why the masked part of the full image is white.
A full code example below:
clear all
pic1 = imread('visionteam.tif');
[x,y,z] = size(pic1);
pzzz = 20-uint8(zeros(x, y, z));
% ADD A DARK GRAY TO BACKGROUND IMAGE TO SEE IF CIRCLE LOSES BACKGROUND WHITE AREA
pC = imread('Circle1000x1000.tif'); % 1000 X 1000 BLACK CIRCLE WITH WHITE BACKGROUND
bbox = [86 52 70 70]; % X Y H W
pC = imresize(pC,[bbox(1,3), bbox(1,4)]); % RESIZE CIRCLE TO BB DIMENSIONS
bCx = bbox(1,1):bbox(1,1)+bbox(1,3)-1; % FIND X AND Y AREA OF BB
bCy = bbox(1,2):bbox(1,2)+bbox(1,3)-1;
mask = imadd(pic1(bCx,bCy,:),pC); % ADD Visionteam IMAGE INSIDE CIRCLE
mask = uint8(mask);
pzzz(bCx,bCy,:) = immultiply(uint16(pzzz(bCx,bCy,:)), uint16(mask))/255;
pzzz = uint8(pzzz);
imagesc(pzzz)
  3 Comments

Sign in to comment.

Accepted Answer

Image Analyst
Image Analyst on 4 Apr 2020
Please attach 'visionteam.tif' and 'Circle1000x1000.tif' or two similar images.
What I'd do is to make a mask and then convert to double, then add, and convert back to uint8. Untested code:
% Now sum with opacity factor
factor = 0.5;
sumImage = uint8(factor * double(backgroundImage) + (1 - factor) * teamImage);
% Mask the sum image using bsxfun() function to multiply the mask by each channel individually.
maskedTeamImage = bsxfun(@times, sumImage, cast(circleMask, 'like', sumImage));
% Burn a black circle into the background so we can add them there.
maskedBackgroundImage = bsxfun(@times, backgroundImage, cast(~circleMask, 'like', teamImage));
% Now simply sum them up to fill in the circle with the 50/50 blended circle patch.
outputImage = maskedBackgroundImage + maskedTeamImage; % Initialize
  8 Comments
mark palmer
mark palmer on 4 Apr 2020
Edited: mark palmer on 4 Apr 2020
I'm fiddling with the code...
sumImage produces a rectangular 50/50 sum of image and background. CHECK
maskedTeamImage produces a black circle with white bounding box background on the gray background image.
maskedBackgroundImage doesn't seem to work. Produces a gray circle with black rectangle bounding box around it inside of the gray background. I'm unable to get your code to work.
Image Analyst
Image Analyst on 7 Apr 2020
OK, sorry for the delay. Here is a full demo. It will take a mask and a background image and another faces image and create a new image where the background image and faces image are blended 50/50 inside the mask region and full brightness background outside that mask region.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format short g;
format compact;
fontSize = 18;
fprintf('Beginning to run %s.m ...\n', mfilename);
hFig = figure;
%------------------------------------------------------------------------------
% Read in face image:
rgbImage = imread('visionteam.jpg');
% Display the image.
subplot(2, 4, 1);
imshow(rgbImage, []);
title('Original Grayscale Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
hFig.WindowState = 'maximized'; % May not work in earlier versions of MATLAB.
drawnow;
%------------------------------------------------------------------------------
% Read in mask image:
mask = imread('Circle1000x1000.jpg');
% Binarize
mask = mask(:, :, 1) < 128;
% Resize mask to be the same size as the image.
mask = imresize(mask, [size(rgbImage, 1), size(rgbImage, 2)]);
% Display the image.
subplot(2, 4, 2);
imshow(mask, []);
title('Mask Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
drawnow;
%------------------------------------------------------------------------------
% Read in background image:
backgroundImage = imread('pears.png');
% Resize mask to be the same size as the image.
backgroundImage = imresize(backgroundImage, [size(rgbImage, 1), size(rgbImage, 2)]);
% Display the image.
subplot(2, 4, 3);
imshow(backgroundImage, []);
title('Background Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
drawnow;
% Get masked face image.
% Mask the image using bsxfun() function to multiply the mask by each channel individually. Works for gray scale as well as RGB Color images.
maskedRgbImage = bsxfun(@times, rgbImage, cast(mask, 'like', rgbImage));
% Make half brightness
maskedRgbImage = maskedRgbImage / 2;
% Display the image.
subplot(2, 4, 4);
imshow(maskedRgbImage, []);
title('Masked Face Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
drawnow;
% Get masked background image at full brightness
% Mask the image using bsxfun() function to multiply the mask by each channel individually. Works for gray scale as well as RGB Color images.
maskedBackgroundImage1 = bsxfun(@times, backgroundImage, cast(~mask, 'like', rgbImage));
% Display the image.
subplot(2, 4, 5);
imshow(maskedBackgroundImage1, []);
title('Masked Background Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
drawnow;
% Get masked background image at full brightness
% Mask the image using bsxfun() function to multiply the mask by each channel individually. Works for gray scale as well as RGB Color images.
maskedBackgroundImage2 = bsxfun(@times, backgroundImage, cast(mask, 'like', rgbImage));
% Make half brightness
maskedBackgroundImage2 = maskedBackgroundImage2 / 2;
% Display the image.
subplot(2, 4, 6);
imshow(maskedBackgroundImage2, []);
title('Dimmed Masked Background Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
drawnow;
% Get masked face image.
% Mask the image using bsxfun() function to multiply the mask by each channel individually. Works for gray scale as well as RGB Color images.
finalImage = maskedBackgroundImage1 + maskedBackgroundImage2 + maskedRgbImage;
% Display the image.
subplot(2, 4, 7);
imshow(finalImage, []);
title('Final Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
drawnow;
fprintf('Done running %s.m ...\n', mfilename);
Adapt as needed.

Sign in to comment.

More Answers (1)

DGM
DGM on 5 May 2023
A big part of the confusion here is from attempting to use imadd() and immultiply() as image blending tools when
  1. they are not practical as image blending tools
  2. the images are not scaled such that they could be blended
  3. image blending would not effect compositing in this manner anyway (at least if I'm understanding the intent)
We can work around 1 and 2 thusly:
pic1 = imread('https://www.mathworks.com/matlabcentral/answers/uploaded_files/281870/visionteam.jpg');
[x,y,z] = size(pic1);
% ADD A DARK GRAY TO BACKGROUND IMAGE TO SEE IF CIRCLE LOSES BACKGROUND WHITE AREA
pzzz = zeros(x, y, z)+0.5;
pC = imread('https://www.mathworks.com/matlabcentral/answers/uploaded_files/281869/Circle1000x1000.jpg'); % 1000 X 1000 BLACK CIRCLE WITH WHITE BACKGROUND
bbox = [86 52 70 70]; % X Y H W
pC = imresize(pC,[bbox(1,3), bbox(1,4)]); % RESIZE CIRCLE TO BB DIMENSIONS
bCx = bbox(1,1):bbox(1,1)+bbox(1,3)-1; % FIND X AND Y AREA OF BB
bCy = bbox(1,2):bbox(1,2)+bbox(1,3)-1;
mask = imadd(pic1(bCx,bCy,:),pC); % ADD Visionteam IMAGE INSIDE CIRCLE
mask = uint8(mask);
% immultiply() is not a blending tool
% if you want to use immultiply as a blending tool
% both input images must be unit-scale floating-point
pzzz(bCx,bCy,:) = immultiply(pzzz(bCx,bCy,:),im2double(mask));
pzzz = im2uint8(pzzz);
imshow(pzzz,'border','tight')
Note the comments about the use of immultiply(). Despite its limitations, this does effect a 'multiply' blend, not alpha compositing. Instead of the circular region being the linear combination of foreground and background, it's the foreground region multiplied by 0.5.
Assuming that the goal is to instead have the circular region at some opacity over a colored field, this is how I'd do it. As usual, I'm just going to use MIMT tools because they exist so that I don't have to reinvent the wheel every time. They are succinct and flexible, handling mixed-class and mixed-depth operations without hassle.
% parameters
opacity = 0.5;
bgcolor = [0.43 0.38 0.25]; % any color tuple (1,2,3,or 4 elements)
% read the files
FG = imread('visionteam.jpg');
% generate a soft-edged mask directly
sz = imsize(FG,2); % get image geometry only
mask = drawcircle(sz,[90 75],50);
% compose output image
% output image class is inherited from the BG tuple (double)
outpict = replacepixels(FG,bgcolor,mask*opacity);
imshow2(outpict)
% draw smooth circle
function circ = drawcircle(sz,c,r)
xx = 1:sz(2);
yy = (1:sz(1)).';
circ = sqrt((xx-c(2)).^2 + (yy-c(1)).^2);
circ = min(max(-(circ-r)/2,0),1);
end
Or if my interpretation of intent is incorrect, I can always replicate @Image Analyst's last example for sake of completeness.
% read the files
FG = imread('pears.png');
BG = imread('visionteam.jpg');
mask = imread('Circle1000x1000.jpg');
% resize the off-size example images
sz = imsize(BG,2);
FG = imresize(FG,sz);
mask = imresize(mask,sz);
% compose output image
% output image class is inherited from BG image (uint8)
outpict = replacepixels(FG,BG,iminv(mask)*0.5);
imshow2(outpict)

Community Treasure Hunt

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

Start Hunting!