Calculate distances from region props centroid data to edge of binary shape

8 views (last 30 days)
I have a list of centroid coordinates givebn by region props and a binary map of a structure given made by a freehand trace. Any ideas on how to find the distance to the nearest edge of the binary shape?
I need to also have the regionprops area data for each point presered.
let me know what other information I can provide!

Answers (2)

DGM
DGM on 10 Jul 2021
Depends on how your objects are shaped, but this should be a start:
inpict = rgb2gray(imread('blobs.png'))>32;
S = regionprops(inpict,'centroid');
C = vertcat(S.Centroid);
dmap = bwdist(inpict); % distance from exterior points to edge
dmapi = bwdist(~inpict); % distance from interior points to edge
% shortest distance to edge for either case
D = interp2(dmap,C(:,1),C(:,2)) + interp2(dmapi,C(:,1),C(:,2))
D = 5×1
17.4449 25.0672 8.6016 30.9511 5.0000
imshow(inpict,[]); hold on
plot(C(:,1),C(:,2),'x')
Note that depending on the convexity of the object, the centroid may lie inside or outside the object. This method covers both cases.
  7 Comments
Theodore Fisher
Theodore Fisher on 12 Jul 2021
Cool! wow thank you this seems to do the trick :)
One last thing, is it possible to have the final output be 3 columns, centroids, area of object, and the distance calculated above?
DGM
DGM on 12 Jul 2021
Again, assuming the "closed boundary" method from the prior example (modify if desired):
S = regionprops(L,'centroid','area');
C = vertcat(S.Centroid);
A = vertcat(S.Area);
dmap = bwdist(addborder(edgemap,[1 1],1)); % distance from exterior points to edge
dmapi = bwdist(addborder(~edgemap,[1 1],1)); % distance from interior points to edge
dmap = cropborder(dmap,[1 1]);
dmapi = cropborder(dmapi,[1 1]);
D = interp2(dmap,C(:,1),C(:,2)) + interp2(dmapi,C(:,1),C(:,2))
out = [C A D]
Of course, that's 4 columns, since the list of centroids is 2 columns. You could also use a table instead:
out = table(C,A,D)

Sign in to comment.


Image Analyst
Image Analyst on 11 Jul 2021
Is this what you mean by "each centroids distance from the edge of 1 object across all of them"?
% 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 = 20;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
grayImage = peaks(300)'; % Create sample image of 3 blobs.
% 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 red channel (so the magenta lines will be white).
grayImage = grayImage(:, :, 1);
end
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage, []);
axis('on', 'image');
title('Original Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
hFig = gcf;
hFig.WindowState = 'maximized'; % May not work in earlier versions of MATLAB.
drawnow;
% Binarize
max(grayImage(:))
mask = grayImage > 2.5;
% Display the image.
subplot(2, 2, 2);
imshow(mask, []);
axis('on', 'image');
title('Mask', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
% Find the centroids
props = regionprops(mask, 'Centroid');
xy = vertcat(props.Centroid)
% Plot centroids over image
subplot(2, 2, 3);
imshow(grayImage, []); % Optional : show the original image again. Or you can leave the binary image showing if you want.
hold on;
for k = 1 : size(xy, 1)
hold on;
xCentroid = xy(k, 1);
yCentroid = xy(k, 2);
plot(xCentroid, yCentroid, 'r+', 'LineWidth', 2, 'MarkerSize', 15);
str = sprintf(' %d', k);
text(xCentroid, yCentroid, str, 'FontSize', 20, 'Color', 'r', 'FontWeight', 'bold');
end
% Find boundaries
% 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.
% 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 x.
plot(x, y, 'r-', 'LineWidth', 2); % Plot boundary in red.
end
hold off;
caption = sprintf('%d Outlines, from bwboundaries()', numberOfBoundaries);
title(caption, 'FontSize', fontSize);
axis('on', 'image'); % Make sure image is not artificially stretched because of screen's aspect ratio.
% Display mask again.
subplot(2, 2, 4);
imshow(mask);
hold on;
axis('on', 'image');
title('Lines from other centroids to boundary of blob #3', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
% Draw lines from every centroid to points along the boundary of blob %3.
% First get boundary #3
b3 = boundaries{3};
xb3 = b3(:, 2);
yb3 = b3(:, 1);
% Now draw lines from each centroid to every 10'th pixel on boundary 3
for k = 1 : numberOfBoundaries
if k == 3
continue; % Skip blob #3
end
thisXCentroid = xy(k, 1);
thisYCentroid = xy(k, 2);
% Just go to every 10th one otherwise it's too crowded to see.
x = xb3(1:10:end);
y = yb3(1:10:end);
for k2 = 1 : length(x)
xLine = [thisXCentroid; x(k2)];
yLine = [thisYCentroid; y(k2)];
distance(k, k2) = sqrt(diff(xLine).^2 + diff(yLine).^2);
plot(xLine, yLine, '-', 'LineWidth', 2); % Plot boundary in red.
end
end

Community Treasure Hunt

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

Start Hunting!