Clear Filters
Clear Filters

Isolating circles and blobs as a mask in a binary image

14 views (last 30 days)
I'm trying to isolate the large blobs/circles as a mask in the attached binary image. To get this image, I did use the imfill function to clean up the specific white areas, but I'm wondering how to isolate the large white areas by either size or solid-ness.
I did watch the Image Segmentation Tutorial and it was helpful as I incorporated pieces into my code, which is below. I utilized the regionprops function to get Area and Solidity information, and I am thinking that the ismember function may be the way to go. Although, I haven't been able to isolate the larger white areas. Any thoughts?
%%
% R = imfill(sliderBW, 'holes'); This is the attached image, defined in the workspace as 'R'
%%
R3 = regionprops(R, 'all'); % Using regionprops to get Area and Solidity
numberOfBlobs = size(R3, 1);
%%
% Below is filtering the Area; 15000 as a threshold was arbitrary
allBlobAreas = [R3.Area];
allowableAreaIndexes = (allBlobAreas > 15000);
keeperIndexes = find(allowableAreaIndexes);
keeperBlobsImage = ismember(R, keeperIndexes);
%Below is filtering the Solidity; 0.5 as a threshold was arbitrary
allBlobSolidity = [R3.Solidity];
allowableSolIndexes = (allBlobSolidity <0.5);
keeperIndexesSol = find(allowableSolIndexes);
keeperBlobsImageSol = ismember(R, keeperIndexesSol);
%%
maskedImage = R; % Re-defining image 'R' again
maskedImage(~keeperBlobsImage) = 0; % Area
maskedImage(~keeperBlobsImageSol) = 0; % Solidity
  3 Comments
Aaron Devanathan
Aaron Devanathan on 11 Feb 2021
Edited: Aaron Devanathan on 11 Feb 2021
@KALYAN ACHARJYA Sure, happy to clarify!
The image I had attached to the original post was a binary mask I created after thresholding and using the imfill function to fill in the holes. From that image, the desired result is to isolate the large, circular objects and have that be a mask. I used MSPaint to provide a cartoon example below.
From the code in the original post, I tried the regionprops function in order to get some objects statistics, but even after thresholding the values based on 'Area' and 'Solidity', I wasn't creating the desired mask. Happy to provide more clarification!
darova
darova on 11 Feb 2021
Once you have Area of each blob - sort area and choose a few biggest

Sign in to comment.

Accepted Answer

Image Analyst
Image Analyst on 11 Feb 2021
Edited: Image Analyst on 11 Feb 2021
Try this:
% Demo by Image Analyst
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
imtool close all; % Close all imtool figures if you have the Image Processing Toolbox.
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 16;
%===============================================================================
% Read in gray scale image.
folder = pwd;
baseFileName = 'Image_Feb2021.jpg';
% Get the full filename, with path prepended.
fullFileName = fullfile(folder, baseFileName);
if ~exist(fullFileName, 'file')
% Didn't find it there. Check the search path for it.
fullFileName = baseFileName; % No path this time.
if ~exist(fullFileName, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
[rgbImage, map] = imread(fullFileName);
% Get the dimensions of the image. numberOfColorBands should be = 1.
[rows, columns, numberOfColorBands] = size(rgbImage);
% If it's RGB instead of grayscale, convert it to gray scale.
if numberOfColorBands > 1
grayImage = rgbImage(:, :, 1); % Take red channel.
else
grayImage = rgbImage;
end
% Display the original image.
subplot(2, 3, 1);
imshow(grayImage, []);
axis on;
impixelinfo; % Let user mouse around and see gray level.
caption = sprintf('Original Gray Scale Image : %s', baseFileName);
title(caption, 'FontSize', fontSize, 'Interpreter', 'none');
impixelinfo;
% Enlarge figure to full screen.
g = gcf;
g.WindowState = 'maximized';
g.NumberTitle = 'off';
g.Name = 'Histogram Analysis';
drawnow;
%===============================================================================
% Display the histogram
subplot(2, 3, 2);
[pixelCounts, grayLevels] = imhist(grayImage);
bar(grayLevels, pixelCounts);
grid on;
title('Original Gray Scale Image Histogram', 'FontSize', fontSize);
xlabel('Gray Level', 'FontSize', fontSize);
ylabel('Pixel Count', 'FontSize', fontSize);
% Get a binary image
mask = grayImage > 128;
% Get rid of white surround.
mask = imclearborder(mask);
% Display the binary mask image.
subplot(2, 3, 3);
imshow(mask, []);
axis on;
impixelinfo; % Let user mouse around and see gray level.
title('Border-cleared Binary Image', 'FontSize', fontSize, 'Interpreter', 'none');
impixelinfo;
% Ask user for one integer number.
defaultValue = 2000;
titleBar = 'Min Blob Size';
userPrompt = 'Enter the minimum size for blobs you would like to extract : ';
dialogBoxWidth = 80;
caUserInput = inputdlg(userPrompt, titleBar, [1, dialogBoxWidth], {num2str(defaultValue)});
if isempty(caUserInput),return,end % Bail out if they clicked Cancel.
% Round to nearest integer in case they entered a floating point number.
minBlobSize = round(str2double(cell2mat(caUserInput)));
% Check for a valid integer.
if isnan(minBlobSize)
% They didn't enter a number.
% They clicked Cancel, or entered a character, symbols, or something else not allowed.
minBlobSize = defaultValue;
message = sprintf('I said it had to be an integer.\nTry replacing the user.\nI will use %d and continue.', minBlobSize);
uiwait(warndlg(message));
end
% Get rid of blobs less than that many pixels in area.
mask = bwareaopen(mask, minBlobSize);
% Display the binary mask image.
subplot(2, 3, 4);
imshow(mask, []);
axis on;
impixelinfo; % Let user mouse around and see gray level.
caption = sprintf('With Only Blobs %d or Larger', minBlobSize);
title(caption, 'FontSize', fontSize, 'Interpreter', 'none');
impixelinfo;
% Find out the areas
props = regionprops(mask, 'Area');
allAreas = sort([props.Area], 'ascend')
% Show distribution of areas:
subplot(2, 3, 5:6);
histogram(allAreas);
counts = histcounts(allAreas);
caption = sprintf('Area Distribution of %d Blobs %d Pixels or Larger', length(allAreas), minBlobSize);
title(caption, 'FontSize', fontSize);
xlabel('Area in Pixels', 'FontSize', fontSize);
ylabel('Blob Count', 'FontSize', fontSize);
grid on;
  4 Comments
Aaron Devanathan
Aaron Devanathan on 14 Feb 2021
@Image Analyst This worked great! The only thing I altered was reversing the less than sign to a greater than sign for the circularities in the line defining the variable 'goodIndexes'. Thank you for your help!
Image Analyst
Image Analyst on 14 Feb 2021
The circularity by my formula is 1 for a circle and grows from there as the perimeter gets more tortuous. For example an asterisk shape will have a circularity of 6 or 10 or more. So if you want circular shapes, you'll want circularities less than about 2 or 3.
If you say circularities > circularitythreshold then you are specifying the least circular, most tortuous shapes.

Sign in to comment.

More Answers (0)

Products


Release

R2018a

Community Treasure Hunt

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

Start Hunting!