Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

To resolve issues starting MATLAB on Mac OS X 10.10 (Yosemite) visit: http://www.mathworks.com/matlabcentral/answers/159016

How can I extract the largest blob in a binary image

Asked by leon on 26 Mar 2013

0 Comments

leon

3 Answers

Answer by Image Analyst on 26 Mar 2013

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

7 Comments

leon on 25 Apr 2013

end of my code not have end

Image Analyst on 25 Apr 2013

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?

leon on 1 May 2013

Image Analyst,

i want ask how to use the ellipse image overlaying the original image?

original image http://snag.gy/o57Ph.jpg

ellipse image http://snag.gy/dJ2aa.jpg

thank you.

Image Analyst
Answer by leon on 25 Apr 2013

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?

0 Comments

leon
Answer by Sean de Wolski on 1 May 2013

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

Image Analyst on 1 May 2013

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?

leon on 1 May 2013

Walter Roberson,

Display new array that has the data for the ellipse written into it.

Image Analyst on 2 May 2013

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);
Sean de Wolski

Contact us