I want to measure the diameter of this image how can i do it ?
7 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Respuesta aceptada
Image Analyst
el 22 de Dic. de 2021
@BERG the problem is the radius is not the same everywhere because the droplet tapers towards the top. So if you want the diameter as defined by the bottom, where it's pretty circular, and not affected by the top, where it's not circular, then you need to ignore the top. In the image down below, look at the green outline. You don't want reginoprops() to get the equivalent diameter of that I wouldn't think. And you can't just chop off the top and use regionprops because the flat-topped droplet is not circular.
So the approach I'm taking is to find the perimeter of the droplet. Then take only the perimeter points below line 150, which is about where the droplet becomes circular. Then fit those coordinates to a circle using the function in the FAQ. If you do that you see the diameter is 325.4 pixels. Here is the full code:
% 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 = 15;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
fileName = 'droplet.jpeg';
grayImage = imread(fileName);
% 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.
% Extract the blue channel (so the magenta lines will be white).
grayImage = grayImage(:, :, 3);
end
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage, []);
impixelinfo;
axis('on', 'image');
caption = sprintf('Original image is %d rows by %d columns', rows, columns);
title(caption, 'FontSize', fontSize);
hold on
drawnow;
% Maximize window.
g = gcf;
g.WindowState = 'maximized'
drawnow;
% Display the histogram.
subplot(2, 2, 2);
imhist(grayImage);
grid on;
impixelinfo;
title('Histogram', 'FontSize', fontSize);
drawnow; % Force screen to refresh immediately.
% Get a binary image
threshold = 80;
xline(threshold, 'Color', 'r', 'LineWidth', 2)
mask = grayImage > 80;
% For noise reduction, Fill any potential holes and take the largest blob.
mask = bwareafilt(imfill(mask, 'holes'), 1);
% Display the image.
subplot(2, 2, 3);
imshow(mask, []);
impixelinfo;
axis('on', 'image');
title('Mask', 'FontSize', fontSize);
hold on
drawnow;
% 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.
hold on;
% 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
% Now get only those boundary points below 100 since the top of the droplet is distorted
% and will not give an accurate radius because of that.
b = boundaries{1};
xb = b(:, 2);
yb = b(:, 1);
topLine = 150;
plot(xb, yb, 'g-', 'LineWidth', 3)
yline(topLine, 'Color', 'r', 'LineWidth', 3)
indexes = yb > topLine;
% Extract only those boundary points below the top line
xb = xb(indexes);
yb = yb(indexes);
% Fit a circle to it.
[xCenter, yCenter, radius, a] = circlefit(xb, yb)
% Display circle.
viscircles([xCenter, yCenter], radius, 'Color', 'r', 'LineWidth', 2)
% Plot cross hairs at the center.
plot(xCenter, yCenter, 'r+', 'MarkerSize', 100, 'LineWidth', 2)
caption = sprintf('Original image with overlays\nDiameter = %.1f, Radius = %.1f', 2*radius, radius);
title(caption, 'FontSize', fontSize);
%========================================================================================================
% From FAQ https://matlab.fandom.com/wiki/FAQ#How_can_I_fit_a_circle_to_a_set_of_XY_data.3F
function [xCenter, yCenter, radius, a] = circlefit(x, y)
% circlefit(): Fits a circle through a set of points in the x - y plane.
% USAGE :
% [xCenter, yCenter, radius, a] = circlefit(X, Y)
% The output is the center point (xCenter, yCenter) and the radius of the fitted circle.
% "a" is an optional output vector describing the coefficients in the circle's equation:
% x ^ 2 + y ^ 2 + a(1) * x + a(2) * y + a(3) = 0
% by Bucher Izhak 25 - Oct - 1991
numPoints = numel(x);
xx = x .* x;
yy = y .* y;
xy = x .* y;
A = [sum(x), sum(y), numPoints;
sum(xy), sum(yy), sum(y);
sum(xx), sum(xy), sum(x)];
B = [-sum(xx + yy) ;
-sum(xx .* y + yy .* y);
-sum(xx .* x + xy .* y)];
a = A \ B;
xCenter = -.5 * a(1);
yCenter = -.5 * a(2);
radius = sqrt((a(1) ^ 2 + a(2) ^ 2) / 4 - a(3));
end
Look how well the circle fits now that you ignore the top part of the droplet and just fit the bottom part.
4 comentarios
Image Analyst
el 22 de Dic. de 2021
Berg, your image is not in the same folder as your m-file. So put in this code to browse for your image. Replace this
fileName = 'droplet.jpeg';
grayImage = imread(fileName);
with this:
% Have user browse for a file, from a specified "starting folder."
% For convenience in browsing, set a starting folder from which to browse.
startingFolder = pwd; % or 'C:\wherever';
if ~isfolder(startingFolder)
% If that folder doesn't exist, just start in the current folder.
startingFolder = pwd;
end
% Get the name of the file that the user wants to use.
defaultFileName = fullfile(startingFolder, '*.*');
[baseFileName, folder] = uigetfile(defaultFileName, 'Select a file');
if baseFileName == 0
% User clicked the Cancel button.
return;
end
fullFileName = fullfile(folder, baseFileName);
grayImage = imread(fullFileName);
Más respuestas (1)
Matt J
el 22 de Dic. de 2021
Editada: Matt J
el 22 de Dic. de 2021
Perhaps as follows,
load Image
stats=bwferet(Image>75,'all')
3 comentarios
Image Analyst
el 23 de Dic. de 2021
Berg if you just binarize the whole thing then you'd be getting the equivalent circular diameter of something like an ellipse. In that case you'd be better off asking for the 'MajorAxisLength' and 'MinorAxisLength', which are the axes you'd get from fitting the blob to an ellipse rather than a circle.
Or else you can fit the ellipse yourself like it says in the FAQ:
or use the attached function.
Ver también
Categorías
Más información sobre Image Processing Toolbox en Help Center y File Exchange.
Productos
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!