Find circle in image

3 次查看(过去 30 天)
Thomas Themelis -CHIS-
Hi all,
I have a z-stack of SEM images of 8000 x 8000 pixels (different slices of a glass capillary with a structure inside it) on which i want to perform some measurments. After some attempts with Gaussian filtering and adaptive binarization I brought the image to the point you can see in the attachement (Initial image on the left and binarized on the right). What i want to do now is detect the circular structure and if possible create a white line at the circumference of the capillary (or just close the existing border by connecting the white pxls wherever there are gaps) in order to have a distinct closed border between the structure and the black background of the image, so that i can be able to perform my measurments (at a later step i would need to do this throughout the whole stack of images). I tried with the imfindcircles function on the image in attachment but it keeps on running without a result for long time probably due to the size of the image. I am far from being an image analysis expert and i don't know how feasible is such an idea, so i could really use any advice on this. Thank a lot in advance people!

回答(2 个)

Matt J
Matt J 2023-3-3
编辑:Matt J 2023-3-3
How about this (requires this Download),
load BWImage
BW0=BW;
se=strel('disk',5);
BW=imclose( bwareaopen(BW,3), se );
BW=bwareafilt(BW,3);
BW=bwmorph(bwconvhull(BW),'remove');
[I,J]=find(BW);
fobj=circularFit([J,I]');
imshow(BW0); hold on
viscircles(fobj.center,fobj.radius); hold off

Image Analyst
Image Analyst 2023-3-3
Try this well commented program.
% 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 = 18;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN TEST IMAGE
folder = [];
baseFileName = 'figure comparison.bmp';
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~exist(fullFileName, 'file')
% The file doesn't exist -- didn't find it there in that folder.
% Check the entire search path (other folders) for the file by stripping off the folder.
fullFileNameOnSearchPath = baseFileName; % No path this time.
if ~exist(fullFileNameOnSearchPath, '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.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
if numberOfColorChannels > 1
% It's not really gray scale like we expected - it's color.
fprintf('It is not really gray scale like we expected - it is color\n');
% Extract the blue channel.
grayImage = rgb2gray(grayImage);
end
% Get the right half that is the binary image. (Because original poster gave us a screenshot instead of an image.)
grayImage = grayImage(:, columns/2+1:end);
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage, []);
impixelinfo;
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Update the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
% Maximize window.
g = gcf;
g.WindowState = 'maximized';
drawnow;
%--------------------------------------------------------------------------------------------------------
% Threshold to create mask
lowThreshold = 128;
highThreshold = 255;
% Interactively and visually set a threshold on a gray scale image.
% https://www.mathworks.com/matlabcentral/fileexchange/29372-thresholding-an-image?s_tid=srchtitle
% [lowThreshold, highThreshold] = threshold(lowThreshold, highThreshold, grayImage)
mask = grayImage >= lowThreshold & grayImage <= highThreshold;
subplot(2, 2, 2);
% Get rid of blobs touching border. (Because original poster gave us a screenshot instead of an image.)
mask = imclearborder(mask);
imshow(mask);
impixelinfo;
axis('on', 'image');
title('Binary/Mask Image', 'FontSize', fontSize, 'Interpreter', 'None');
%--------------------------------------------------------------------------------------------------------
% TURN THE NOISY MASK INTO A SINGLE CIRCULAR MASK.
mask = imclose(mask, true(9));
% Take only the largest blob.
mask = bwareafilt(mask, 1);
% Get the convex hull
mask = bwconvhull(mask, "union");
% Display image.
subplot(2, 2, 3);
imshow(mask);
impixelinfo;
axis('on', 'image');
title('Cleaned Mask Image', 'FontSize', fontSize, 'Interpreter', 'None');
%--------------------------------------------------------------------------------------------------------
% GET THE BORDERS OF THE CIRCULAR MASK.
% 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.
subplot(2, 2, 4);
imshow(grayImage); % 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.
You have the binary image mask as variable "mask" as well as the (x,y) coordinates of the red boundary line in variables x and y.
  1 个评论
Thomas Themelis -CHIS-
Thanks a lot for the input Image Analyst! I was trying to adapt your program for the original [8000x8000] pxls binary tif image but i cannot make it work. My interpretation was that since the original image is not a gray image the thresholding performed does not work. Is this the case? Is there a workaround on this? I tried to make this work in an indirect way, by resizing the mask to match the size of the original tif image or the grayImage to match the size of the original tif but still i cannot get it to work exactly and apart from that it doesn't feel like the correct thing to do. This time i am attaching the correct tif image in a zip format. Sorry for providing the wrong format the last time :)

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Image Processing Toolbox 的更多信息

产品


版本

R2022b

Community Treasure Hunt

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

Start Hunting!

Translated by