How to display multiple ROI (masks) in different colors on one image?

27 views (last 30 days)
I have problem displaying multiple ROI(masks) on one image. I am able to display one mask on the image, and then imfuse the images at the end. But this means that the colors of each mask becomes increasingly transparent, and i would like to avoid that. Please support with ideas and upgrades to the current code.
clc; % Clear command window.
clear; % Delete all variables.
close all; % Close all figure windows except those created by imtool.
imtool close all; % Close all figure windows created by imtool.
workspace; % Make sure the workspace panel is showing.
fontSize = 16;
Image = imread('Report_Picture.png');
[rows, columns, numberOfColorChannels] = size(Image);
imshow(Image, []);
axis on;
title('Report Image', 'FontSize', fontSize);
% set(gcf, 'Position', get(0,'Screensize')); % Maximize figure.
message = sprintf('1 freehand');
uiwait(msgbox(message));
roi = images.roi.AssistedFreehand;
draw(roi);
message = sprintf('2 freehand');
uiwait(msgbox(message));
roi2 = images.roi.AssistedFreehand;
draw(roi2);
message = sprintf('3 freehand');
uiwait(msgbox(message));
roi3 = images.roi.AssistedFreehand;
draw(roi3);
message = sprintf('4 freehand');
uiwait(msgbox(message));
roi4 = images.roi.AssistedFreehand;
draw(roi4);
mask1 = createMask(roi);
mask2 = createMask(roi2);
mask3 = createMask(roi3);
mask4 = createMask(roi4);
% % Display the freehand mask.
% imshow(mask3);
% axis on;
% title('Binary mask of the region', 'FontSize', fontSize);
% If it's grayscale, convert to color
if numberOfColorChannels < 3
rgbImage = cat(3, Image, Image, Image);
else
% It's really an RGB image already.
rgbImage = Image;
end
% Extract the individual red, green, and blue color channels.
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
redChannel2 = rgbImage(:, :, 1);
greenChannel2 = rgbImage(:, :, 2);
blueChannel2 = rgbImage(:, :, 3);
redChannel3 = rgbImage(:, :, 1);
greenChannel3 = rgbImage(:, :, 2);
blueChannel3 = rgbImage(:, :, 3);
redChannel4 = rgbImage(:, :, 1);
greenChannel4 = rgbImage(:, :, 2);
blueChannel4 = rgbImage(:, :, 3);
% Specify the color we want to make this area.
desiredColor1 = [235, 18, 22]; % Red
desiredColor2 = [0, 255, 0]; % Green
desiredColor3 = [251, 255, 0]; % Yellow
desiredColor4 = [251, 255, 0]; % Yellow
% Make the red channel that color
redChannel(mask1) = desiredColor1(1);
greenChannel(mask1) = desiredColor1(2);
blueChannel(mask1) = desiredColor1(3);
redChannel2(mask2) = desiredColor2(1);
greenChannel2(mask2) = desiredColor2(2);
blueChannel2(mask2) = desiredColor2(3);
redChannel3(mask3) = desiredColor3(1);
greenChannel3(mask3) = desiredColor3(2);
blueChannel3(mask3) = desiredColor3(3);
redChannel4(mask4) = desiredColor4(1);
greenChannel4(mask4) = desiredColor4(2);
blueChannel4(mask4) = desiredColor4(3);
% Recombine separate color channels into a single, true color RGB image.
rgbImage1 = cat(3, redChannel, greenChannel, blueChannel);
imwrite(rgbImage1,'C:\Users\phillip.wulff\Ergo Files\Report\Pictures\Picture1.png');
rgbImage2 = cat(3, redChannel2, greenChannel2, blueChannel2);
imwrite(rgbImage2,'C:\Users\phillip.wulff\Ergo Files\Report\Pictures\Picture2.png');
rgbImage3 = cat(3, redChannel3, greenChannel3, blueChannel3);
imwrite(rgbImage3,'C:\Users\phillip.wulff\Ergo Files\Report\Pictures\Picture3.png');
rgbImage4 = cat(3, redChannel4, greenChannel4, blueChannel4);
imwrite(rgbImage4,'C:\Users\phillip.wulff\Ergo Files\Report\Pictures\Picture4.png');
% Display the image.
A = imfuse(rgbImage1,rgbImage2,'blend','Scaling','none');
A = imfuse(A,rgbImage3,'blend','Scaling','none');
A = imfuse(A,rgbImage4,'blend','Scaling','none');
imshow(A);
title('Image with color inside the mask region', 'FontSize', fontSize);

Answers (1)

DGM
DGM on 19 Jul 2021
I know this is probably too late to help, but consider this:
fontSize = 16;
Image = imread('Report_Picture.png');
[rows, columns, numberOfColorChannels] = size(Image);
imshow(Image, []);
axis on;
title('Report Image', 'FontSize', fontSize);
disp('Make freehand selection 1 of 4')
%message = sprintf('1 freehand');
%uiwait(msgbox(message)); % wow that's annoying
roi = images.roi.AssistedFreehand;
draw(roi);
disp('Make freehand selection 2 of 4')
roi2 = images.roi.AssistedFreehand;
draw(roi2);
disp('Make freehand selection 3 of 4')
roi3 = images.roi.AssistedFreehand;
draw(roi3);
disp('Make freehand selection 4 of 4')
roi4 = images.roi.AssistedFreehand;
draw(roi4);
mask1 = createMask(roi);
mask2 = createMask(roi2);
mask3 = createMask(roi3);
mask4 = createMask(roi4);
% If it's grayscale, convert to color
if numberOfColorChannels < 3
rgbImage = cat(3, Image, Image, Image);
else
% It's really an RGB image already.
rgbImage = Image;
end
% Specify the color we want to make this area.
desiredColor1 = [235, 18, 22]; % Red
desiredColor2 = [0, 255, 0]; % Green
desiredColor3 = [251, 255, 0]; % Yellow
desiredColor4 = [251, 255, 0]; % Yellow
% generate overlays from masks
olay1 = 255-mask1.*permute(255-desiredColor1,[1 3 2]);
olay2 = 255-mask2.*permute(255-desiredColor2,[1 3 2]);
olay3 = 255-mask3.*permute(255-desiredColor3,[1 3 2]);
olay4 = 255-mask4.*permute(255-desiredColor4,[1 3 2]);
alloverlays = (olay1 + olay2 + olay3 + olay4)/4;
% combine overlay with image
A = uint8((double(rgbImage) + alloverlays)/2);
% Display the image.
imshow(A);
title('Image with color inside the mask region', 'FontSize', fontSize);
There are a lot of ways you can combine images, but using something like imfuse() can become cumbersome and limiting. The above is the source image averaged with the average of overlays. In this way all overlays are transparent, they have the same weight and the source is subdued.
If you don't want the background subdued, just do a darken-only blend:
A = min(uint8(alloverlays),rgbImage);
If you actually want the masked regions to not be transparent, then it'll have to be decided whether they should be transparent with respect to each other, otherwise overlapping regions will obscure each other (might not matter if they never overlap). Let's assume that they can blend with each other, but not the source image:
allmasks = repmat(mask1|mask2|mask3|mask4,[1 1 3]);
A = rgbImage;
A(allmasks) = uint8(alloverlays(allmasks));
If they should stack atop each other, then alloverlays would be calculated differently.
  7 Comments
Gwendolyn Williams
Gwendolyn Williams on 18 Feb 2022
Thank you for all of this! Truly, the multiple examples and detailed explanations are extremely helpful. I tend to get confused with understanding what items need to be of what types and why, and the nuanced differences between functionality of different data types. I was able to get each of your examples to work on my end, and MIMT is going to be very helpful for me going forwards with this specific project. Again, thank you so much for this detailed and informative response!!
DGM
DGM on 18 Feb 2022
FWIW, that package also includes imcast(), which is basically a replacement for im2uint8(), im2double(), etc. Its advantage is that the class name is a parameter. This allows you to simplify workflows to avoid having to deal with potential dependency on the class of the input image. Trying to do the same with the IPT tools requires a bunch of conditionals and is kind of a hassle.
% say you read in some image that might be of any class
inpict = imread('cameraman.tif');
% regardless of class of inpict, cast & scale to double
% but keep track of its original class
[workingpict inclass] = imcast(inpict,'double');
% do a bunch of hypothetical operations with other floating-point arrays
% that might break if workingpict were integer-class
npict = rand(size(workingpict));
workingpict = workingpict.*npict;
% at the end of the script or function
% cast & scale the result so that it matches the original image
outpict = imcast(workingpict,inclass);
Of course, always working in floating point is expensive in terms of memory, but it is at least consistent and generally more convenient to write.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!