Need a help with a code to check if a circle in a image is closed or not
Show older comments
As the thread title describes it very well, I need help with my code. I have to check a binary image, if the circle is closed or not. Therefore I want the code to go into the middle of the image matrix (column direction) and go down, until he finds a 0 (black pixel) afterwards I want to check the in clockwise direction for another black pixel. Therfore it should move next column and check if it is a 0 or 1. If 0 go one row down and continue, otherwise go to next column. In this way, I think it will work. If the code does not find the next 0, the contour is open. I hope my logic is correct. Perhaps there is already an command for that. bwtraceboundaries, does not give out an output if the contour is closed or not. So it does not help me.
Thanks in advance.
6 Comments
Image Analyst
on 24 Nov 2023
Moved: Matt J
on 24 Nov 2023
You can use regionprops to look at the Circularity measurement. The circle will have a circularity near 1 while rectangles will be much less than that. Make sure your objects are white though, not black, so invert your mask.
props = regionprops(mask, 'Circularity'); % Measure circularity of all white blobs.
allCirc = [props.Circularity] % Extract into a single vector.
circIndexes = find(allCirc > 0.9); % Get indexes of circles
labeledImage = bwlabel(mask); % Get an ID number for each blob.
% Extract only the blobs that are circles into a new image.
circleOnlyImage = ismember(labeledImage, circIndexes);
Matt J
on 24 Nov 2023
So I need help again....
Please don't seek it here. Please post a new question.
Matt J
on 25 Nov 2023
I think the problem is a little bit more complex.
That's fine but since it's a different problem from what you posted, and what we've provided answers to below, please relaunch the discussion in a new thread.
Accepted Answer
More Answers (2)
I would just use imfill(__,'holes'). If there are any breaks in the boundaries, it will fail to fill the circle.
12 Comments
I put an image of my simple circle problem.
It would be better if you put it in a .mat file attachment. Seeing your code
like this
would also help to determine what is wrong.
Matt J
on 19 Nov 2023
Well, you should definitely flip black to white for the processing. I cannot really demonstrate because you've accidentally attached your code instead of the image.
Harak
on 19 Nov 2023
Harak
on 19 Nov 2023
It does give you an answer. If there is a gap, imfilll will do nothing and you will see no change in the white pixel area. If there is no gap, imfill will fill the interior of the circle and you will see a significant increase in white pixel area. It is on that basis that you can distinguish between circles thar are whole and those that are not.
Harak
on 19 Nov 2023
Matt J
on 19 Nov 2023
You're welcome, but if it ends up working, please Accept-click the answer.
Image Analyst
on 19 Nov 2023
What I'd do is to call regionprops and ask for the Solidity of the blob(s). If the solidity is close to 1, then it's closed. If it's less, then it's more like the C shape you showed. Untested code:
props = regionprops(binaryImage, 'Solidity');
allSolidities = [props.Solidity]
for k = 1 : numel(props)
if allSolidities(k) > 0.8
fprintf('Blob #%d is closed.\n', k);
else
fprintf('Blob #%d is NOT closed.\n', k);
end
end
7 Comments
Harak
on 19 Nov 2023
Image Analyst
on 19 Nov 2023
Then you have two blobs. Maybe one is just too small for you to see. You can display them one at a time with ismember() or this code:
% Plot the borders of all the blobs in the overlay above the original grayscale image
% using the coordinates returned by bwboundaries().
% bwboundaries() returns a cell array, where each cell contains the row/column coordinates for an object in the image.
imshow(originalImage); % Optional : show the original image again. Or you can leave the binary image showing if you want.
% Here is where we actually get the boundaries for each blob.
boundaries = bwboundaries(mask);
% boundaries is a cell array - one cell for each blob.
% In each cell is an N-by-2 list of coordinates in a (row, column) format. Note: NOT (x,y).
% Column 1 is rows, or y. Column 2 is columns, or x.
numberOfBoundaries = size(boundaries, 1); % Count the boundaries so we can use it in our for loop
% Here is where we actually plot the boundaries of each blob in the overlay.
hold on; % Don't let boundaries blow away the displayed image.
for k = 1 : numberOfBoundaries
thisBoundary = boundaries{k}; % Get boundary for this specific blob.
x = thisBoundary(:,2); % Column 2 is the columns, which is x.
y = thisBoundary(:,1); % Column 1 is the rows, which is y.
plot(x, y, 'r-', 'LineWidth', 2); % Plot boundary in red.
end
hold off;
caption = sprintf('%d Outlines, from bwboundaries()', numberOfBoundaries);
fontSize = 15;
title(caption, 'FontSize', fontSize);
axis('on', 'image'); % Make sure image is not artificially stretched because of screen's aspect ratio.
The solidity is the ratio of the actual object area to the convex hull of the area (like the area you'd get if you wrapped a rubber band around the blob).
There are cases where neither the EulerNumber not the Solidity would identify every possible situation. That's why it's important to see real images, not computer generated images.
Note: I will be out for the next several hours visiting friends.
Harak
on 19 Nov 2023
Seems to me like it worked. It found two blobs, which upon further examination you said were actually there. And it classified them correctly.
However there are some cases where the two approaches differ. Since you won't show us your original images I had to synthesize some. Look at these, especially the right-most image, which I made because I think that if your perimeter is faint enough to be broken, then it might also be faint enough to have some interior holes in the perimeter.

Would you consider an outline with some small black specks in an otherwise closed perimeter to be closed or not?
Now look at this code and see how two approached differ in how they classifiy the right image. Solidity calls it closed while EulerNumber says it's not closed.
% Demo by Image Analyst
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
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;
markerSize = 20;
%--------------------------------------------------------------------------------------------------------
% READ IN TEST IMAGE
folder = pwd;
baseFileName = 'harak circle.png';
fullFileName = fullfile(folder, baseFileName);
grayImage = imread(fullFileName);
% Convert to binary
binaryImage = grayImage > 128;
%--------------------------------------------------------------------------------------------------------
% Display the image.
imshow(binaryImage, []);
impixelinfo;
axis('on', 'image');
title('Original Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Maximize window.
g = gcf;
g.WindowState = 'maximized';
g.Name = 'Demo by Image Analyst';
g.NumberTitle = 'off';
drawnow;
%--------------------------------------------------------------------------------------------------------
% Method using solidity.
% Fill any black holes that are inside the white regions.
binaryImageFilled = imfill(binaryImage, 'holes');
props = regionprops(binaryImageFilled, 'Solidity');
allSolidities = [props.Solidity]
for k = 1 : numel(props)
if allSolidities(k) > 0.8
fprintf('Solidity says blob #%d is closed.\n', k);
else
fprintf('Solidity says blob #%d is NOT closed.\n', k);
end
end
%--------------------------------------------------------------------------------------------------------
% Method using EulerNumber.
% EulerNumber = Number of objects in the region minus the number of holes in those objects.
% So EulerNumber = 1 for closed objects such as the left image (1 region, 0 holes).
% EulerNumber = 0 for objects such as the second image (1 region, 1 hole).
% So EulerNumber = -2 for objects such as the third image (1 region, 3 holes).
% So EulerNumber = -3 for objects such as the fourth image (1 region, 4 holes).
% Note how the two methods differ in how they classify the 4th (right) image.
props = regionprops(binaryImage, 'EulerNumber');
allEulerNumbers = [props.EulerNumber]
for k = 1 : numel(props)
if allEulerNumbers(k) == 0
fprintf('Euler says blob #%d is closed.\n', k);
else
fprintf('Euler says blob #%d is NOT closed.\n', k);
end
end
One way to get rid of internal holes below a certain area is using bwlalphaclose from this FEX download,
load BubblyRing
Iclose=bwlalphaclose(I,1,'objects','HoleThreshold',250);
figure; subplot(1,2,1); imshow(I,[]); subplot(1,2,2); imshow(Iclose,[])
load ClosedRing
Iclose=bwlalphaclose(I,1,'objects','HoleThreshold',250);
figure; subplot(1,2,1); imshow(I,[]); subplot(1,2,2); imshow(Iclose,[])
Image Analyst
on 20 Nov 2023
Edited: Image Analyst
on 20 Nov 2023
I believe I've already let Steve Eddins know of the need to have an option for bwareaopen or imfill to have only holes in a certain size range removed.
Harak
on 20 Nov 2023
Categories
Find more on Blue in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!





