MATLAB: How to remove square shape part from image and detect the bubbles around squares

image analysisimage processingImage Processing Toolboximage segmentationmaskmasking

Best Answer

OK Suresh, here's the full demo. It's exceptionally well commented so it's self explanatory. Adapt as needed:
% Demo to mask square tile and bubbles out of an RGB image. By Image Analyst, March 26, 2020.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clearvars;
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 16;
% Define image name. Adapt for your particular image, or use uigetfile().
% folder = pwd;
baseFileName = 'image.jpeg';
fullFileName = fullfile(folder, baseFileName);
rgbImage = imread(fullFileName);
[rows, columns, numberOfColorChannels] = size(rgbImage);
% Display the original image.
imshow(rgbImage, []);
axis('on', 'image');
caption = sprintf('Original Color Image\n"%s"', baseFileName);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.






% Set up figure properties:
% Enlarge figure to full screen.
hFig = gcf;
hFig.Units = 'Normalized';
hFig.WindowState = 'maximized';
% Get rid of tool bar and pulldown menus that are along top of figure.
% set(gcf, 'Toolbar', 'none', 'Menu', 'none');
% Give a name to the title bar.
hFig.Name = 'Demo by Image Analyst';
hFig.NumberTitle = 'Off'
% Option 1: MANUAL MASKING.
% To have the user mask the image, use the following 5 lines of code:
% title('Left click the vertices of the square tile, except right click the last one to finish it.', 'FontSize', fontSize);
% uiwait(helpdlg('Left click the vertices of the square tile, except right click the last one to finish it.'));
% [squareMask, xv, yv] = roipolyold();
% xv
% yv
% OPTION 2: AUTOMATIC MASKING BASED ON PREDETERMINED COORDINATES.
% OR, if you have xv and yv already somehow (like from a prior manual masking)
% you can use poly2mask(). But you don't need to do it both ways.
xv = [...
174.840588988476
191.434699103713
515.3271446863
497.503841229193
174.840588988476];
yv = [...
94.2259923175416
421.806017925736
402.138924455826
76.4026888604353
94.2259923175416];
squareMask = poly2mask(xv, yv, rows, columns);
% Now get the mask of the surround. It's all white and touches the border.
thresholdLevel = 200; % Minimum brightness allowed to be called "surround".
surroundMask = rgbImage(:,:,1) >= thresholdLevel & rgbImage(:,:,2) >= thresholdLevel & rgbImage(:,:,3) >= thresholdLevel;
% Find out which blobs do NOT touch the border.
insideBlobs = imclearborder(surroundMask);
% Erase those inside blobs from the mask.
surroundMask(insideBlobs) = false;
% Now there may be some small holes in the mask. Fill those holes that are smaller than 100 x 100 pixels.
surroundMask = ~bwareaopen(~surroundMask, 10000);
% Display the original image in the upper left quadrant.
subplot(2, 3, 1);
imshow(rgbImage, []);
axis('on', 'image');
caption = sprintf('Original Color Image\n"%s"', baseFileName);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
% Display the square tile mask.
subplot(2, 3, 2);
imshow(squareMask);
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
title('Binary Image Mask of Square Tile', 'FontSize', fontSize, 'Interpreter', 'None');
% Display the surround mask.

subplot(2, 3, 3);
imshow(surroundMask);
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
title('Surround Mask', 'FontSize', fontSize, 'Interpreter', 'None');
% Now mask the image to get the bubbles, outside the square. So we use ~ to invert the mask.
% It's bubbles if it's not part of the surround AND it's not part of the square tile.
bubbleMask = ~surroundMask & ~squareMask;
% Display the surround mask.
subplot(2, 3, 4);
imshow(bubbleMask);
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
title('Bubble Mask', 'FontSize', fontSize, 'Interpreter', 'None');
% Mask the image using bsxfun() function to multiply the mask by each channel individually.

maskedBubblesRgbImage = bsxfun(@times, rgbImage, cast(bubbleMask, 'like', rgbImage));
% Display the image with the square visible and the bubbles masked out.

subplot(2, 3, 5);
imshow(maskedBubblesRgbImage, []);
axis('on', 'image');
title('Masked Image of Bubbles', 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
% Mask the image using bsxfun() function to multiply the mask by each channel individually.
maskedSquareRgbImage = bsxfun(@times, rgbImage, cast(squareMask, 'like', rgbImage));
% Display the image with the square visible and the bubbles masked out.
subplot(2, 3, 6);
imshow(maskedSquareRgbImage, []);
axis('on', 'image');
title('Masked Image of Square Tile', 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
msgbox('Done!');