How can I extract the largest blob in a binary image

 Accepted Answer

See this demo. Adapt it to use your binary images instead of the binary image I generate from the standard "coins.png' demo image. Save the code below as ExtractBiggestBlob.m and run it. The main part of the function is in a custom function called ExtractNLargestBlobs() that I wrote, and it's included at the bottom of the code. The code above that is just to make a fancy demo with nice pictures to illustrate what's going on.
function ExtractBiggestBlob()
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 = 20;
% Read in a standard MATLAB gray scale demo image.
folder = fullfile(matlabroot, '\toolbox\images\imdemos');
baseFileName = 'coins.png';
% Get the full filename, with path prepended.
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~exist(fullFileName, 'file')
% File doesn't exist -- 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 in the search path folders.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
grayImage = imread(fullFileName);
% Get the dimensions of the image.
% numberOfColorBands should be = 1.
[rows, columns, numberOfColorBands] = size(grayImage);
% Display the original gray scale image.
subplot(2, 2, 1);
imshow(grayImage, []);
title('Original Grayscale Image', 'FontSize', fontSize);
% Enlarge figure to full screen.
set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
% Give a name to the title bar.
set(gcf,'name','Demo by ImageAnalyst','numbertitle','off')
% Let's compute and display the histogram.
[pixelCount, grayLevels] = imhist(grayImage);
subplot(2, 2, 2);
bar(pixelCount);
grid on;
title('Histogram of original image', 'FontSize', fontSize);
xlim([0 grayLevels(end)]); % Scale x axis manually.
% Threshold the image to binarize it.
binaryImage = grayImage > 100;
% Fill holes
binaryImage = imfill(binaryImage, 'holes');
% Display the image.
subplot(2, 2, 3);
imshow(binaryImage, []);
title('Binary Image', 'FontSize', fontSize);
% Get all the blob properties. Can only pass in originalImage in version R2008a and later.
[labeledImage, numberOfBlobs] = bwlabel(binaryImage);
blobMeasurements = regionprops(labeledImage, 'area', 'Centroid');
% Get all the areas
allAreas = [blobMeasurements.Area] % No semicolon so it will print to the command window.
menuOptions{1} = '0'; % Add option to extract no blobs.
% Display areas on image
for k = 1 : numberOfBlobs % Loop through all blobs.
thisCentroid = [blobMeasurements(k).Centroid(1), blobMeasurements(k).Centroid(2)];
message = sprintf('Area = %d', allAreas(k));
text(thisCentroid(1), thisCentroid(2), message, 'Color', 'r');
menuOptions{k+1} = sprintf('%d', k);
end
% Ask user how many blobs to extract.
numberToExtract = menu('How many do you want to extract', menuOptions) - 1;
% Ask user if they want the smallest or largest blobs.
promptMessage = sprintf('Do you want the %d largest, or %d smallest, blobs?',...
numberToExtract, numberToExtract);
titleBarCaption = 'Largest or Smallest?';
sizeOption = questdlg(promptMessage, titleBarCaption, 'Largest', 'Smallest', 'Cancel', 'Largest');
if strcmpi(sizeOption, 'Cancel')
return;
elseif strcmpi(sizeOption, 'Smallest')
% If they want the smallest, make the number negative.
numberToExtract = -numberToExtract;
end
%---------------------------------------------------------------------------
% Extract the largest area using our custom function ExtractNLargestBlobs().
% This is the meat of the demo!
biggestBlob = ExtractNLargestBlobs(binaryImage, numberToExtract);
%---------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 4);
imshow(biggestBlob, []);
% Make the number positive again. We don't need it negative for smallest extraction anymore.
numberToExtract = abs(numberToExtract);
if numberToExtract == 1
caption = sprintf('Extracted %s Blob', sizeOption);
elseif numberToExtract > 1
caption = sprintf('Extracted %d %s Blobs', numberToExtract, sizeOption);
else % It's zero
caption = sprintf('Extracted 0 Blobs.');
end
title(caption, 'FontSize', fontSize);
msgbox('Done with demo!');
% Function to return the specified number of largest or smallest blobs in a binary image.
% If numberToExtract > 0 it returns the numberToExtract largest blobs.
% If numberToExtract < 0 it returns the numberToExtract smallest blobs.
% Example: return a binary image with only the largest blob:
% binaryImage = ExtractNLargestBlobs(binaryImage, 1)
% Example: return a binary image with the 3 smallest blobs:
% binaryImage = ExtractNLargestBlobs(binaryImage, -3)
function binaryImage = ExtractNLargestBlobs(binaryImage, numberToExtract)
try
% Get all the blob properties. Can only pass in originalImage in version R2008a and later.
[labeledImage, numberOfBlobs] = bwlabel(binaryImage);
blobMeasurements = regionprops(labeledImage, 'area');
% Get all the areas
allAreas = [blobMeasurements.Area];
if numberToExtract > 0
% For positive numbers, sort in order of largest to smallest.
% Sort them.
[sortedAreas, sortIndexes] = sort(allAreas, 'descend');
elseif numberToExtract < 0
% For negative numbers, sort in order of smallest to largest.
% Sort them.
[sortedAreas, sortIndexes] = sort(allAreas, 'ascend');
% Need to negate numberToExtract so we can use it in sortIndexes later.
numberToExtract = -numberToExtract;
else
% numberToExtract = 0. Shouldn't happen. Return no blobs.
binaryImage = false(size(binaryImage));
return;
end
% Extract the "numberToExtract" largest blob(a)s using ismember().
biggestBlob = ismember(labeledImage, sortIndexes(1:numberToExtract));
% Convert from integer labeled image into binary (logical) image.
binaryImage = biggestBlob > 0;
catch ME
errorMessage = sprintf('Error in function ExtractNLargestBlobs().\n\nError Message:\n%s', ME.message);
fprintf(1, '%s\n', errorMessage);
uiwait(warndlg(errorMessage));
end

14 Comments

Change the three lines starting from (including)
% Read in a standard MATLAB gray scale demo image.
Why can't your code run? Why do you need edge code anyway? What does your original image look like? All I saw was the image of the square that had already been binarized. You got it once before (because you uploaded it for us), so why can't you get it now? Are there any error messages? Where did you upload IMG_147.jpg? Why are you using JPG anyway since it will produce image artifacts - you almost never want to use JPG if you are going to do image analysis on the image.
leon
leon on 25 Apr 2013
Moved: DGM on 12 Feb 2023
i don't know,because want ellipse detect just need object edge line only. if want change picture to format png or tiff just open the image then save as png format?
I don't know what your "Answer" below means. Can you answer my questions I asked above?
I think you have an extra "end" at the end of your code. Take that out.
end of my code not have end
See where your code says this (copied from your answer above):
figure (8), imshow (BW)
end
What is the last word there? It looks like "end" to me. Is that your entire script? You didn't clip out just a portion of it?
Image Analyst,
i want ask how to use the ellipse image overlaying the original image?
thank you.
Hi I really want to cite this code! what should I write in my reference section? Thank you!
Hi Image Analyst, I really want to cite this code! what should I put in my reference section? Thank you!
I'd just put the URL for it.
There is a new function to extract only the largest blob -- it's called bwareafilt()
BW = bwareafilt(BW, 1); % Extract largest blob.
Hi @Image Analyst,
If I have two objects in the image and I want to separate the largest and the smallest in two separate images, how should I proceed?
Use bwareafilt(). For the biggest blob, something like
biggestBlob = bwareafilt(binaryImage, 1);
bigBlob = grayImage; % Initialize.
bigBlob(~biggestBlob) = false; % Erase outside of big blob.
Start a new question if you can't figure it out for the smallest blob or second biggest blob.

Sign in to comment.

More Answers (2)

Here's the function I wrote to do this. You can also use the example in the "tips section of the doc for regionprops which explains how to keep blobs based on some criteria.
function Imx = keepMaxObj(X)
%Function to keep only the maximum sized (biggest) object in an image
%SCd 11/30/2010
%
%Updates:
% -02/03/2011: Added ability to handle an image directly
%
%Usage:
% Imx = keepMaxObj(CC);
% Imx = keepMaxObj(V);
%
%Input Arguments:
% -CC: Connected components returned from bwconncomp
% -V: Logical image with parts you want true
%
%Output Arguments:
% -Imx: Logical volume with only the biggest object left true.
%
%See Also: bwconncomp
%
%Error checking:
assert(islogical(X)||isstruct(X),'The first input argument is expected to be a struct or a logical');
if isstruct(X)
CC = X;
parts = {'PixelIdxList','ImageSize'};
assert(all(ismember(parts,fieldnames(CC))),'CC is expected to be the output from bwconncomp');
else
CC = bwconncomp(X);
end
clear X;
%Preallocate and find number of voxels/object
Nvox = zeros(CC.NumObjects,1);
for ii = 1:CC.NumObjects
Nvox(ii) = numel(CC.PixelIdxList{ii});
end
%Find the biggest object's index, warn and save all if there are multiples
[mx,midx] = max(Nvox);
more_than1_max = sum(mx==Nvox);
if more_than1_max > 1
midx = find(mx == Nvox);
warning('Multiple:Maxima', 'There were %i objects with the maximum size.\n They are all left on!',more_than1_max);
end
%Create the final image
Imx = false(CC.ImageSize);
Imx([CC.PixelIdxList{midx}]) = true;
end

7 Comments

Sean de Wolski,
i don't understand ,where to put the original image and elliipse image? After that how to overlaping both image?
Save this code to a file called "keepMaxObj.m". Then call it with whatever the variable name of your image is:
Imx = keepMaxObj(V)
Where V is whatever you've called your image.
Imx = keepMaxObj (original image), (v) i put orignal image, how about ellipse image where should i put?
When you ask to overlap them, do you mean "in the display", or do you mean that you want to create a new array that has the data for the ellipse written into it as well as the other data ?
Both Sean's function, and the one I gave you (binaryImage = ExtractNLargestBlobs(binaryImage, numberToExtract)) expect the input to be a binary image, meaning a logical (true or false) image. If all you have is the boundary coordinates of your ellipse, then you'd use poly2mask() to create the binary image. How did you get that ellipse you posted above?
Walter Roberson,
Display new array that has the data for the ellipse written into it.
What form is your ellipse in? It looks like an RGB image with some white pixels and some blue pixels - at least the image you posted in the comment to my answer does. Why do you want that blue and white image burned into the image? You can easily do it (but I don't know why you'd want to):
% Extract the individual red, green, and blue color channels.
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
% Extract the individual red, green, and blue color channels
% of the ellipse image.
redEllipseChannel = rgbEllipseImage(:, :, 1);
greenEllipseChannel = rgbEllipseImage(:, :, 2);
blueEllipseChannel = rgbEllipseImage(:, :, 3);
% Get mask
mask = redEllipseChannel > 0 & greenEllipseChannel > 0 & blueEllipseChannel > 0;
% Assign ellipse pixels in the masked region of the ellipse image
% to the original image in the masked region
redChannel(mask) = redEllipseChannel(mask);
greenChannel(mask) = greenEllipseChannel (mask);
blueChannel(mask) = blueEllipseChannel(mask);
% Recombine into RGB image
newRGBimage = cat(3, redChannel, greenChannel, blueChannel);
% Display
imshow(newRGBimage);

Sign in to comment.

I came across the bwpropfilt function, which serves this purpose in one line:
BW2 = bwpropfilt(BW, 'Area', n);
BW2 is the new binary image with only n largest objects in BW.

1 Comment

There is a new function to extract only the largest blob -- it's called bwareafilt()
BW = bwareafilt(BW, 1); % Extract largest blob.

Sign in to comment.

Categories

Asked:

on 26 Mar 2013

Edited:

DGM
on 12 Feb 2023

Community Treasure Hunt

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

Start Hunting!