center to center distance between objects: Need advise

I am trying to calculate center to center distance between lines, i.e., between intersection points. I am working on this image
I want to achieve this
However, following steps I have assumed like
  1. detect centerlines in the image.
  2. detect intersection points.
  3. calculate horizantal distances between intersecting points.
  4. calculate vertical distances between intersecting points.
I am a bit confused about functions to be applied here. If anyone can advice which fucntions will be helpful to be to achieve above outcome OR if there is some better methodlogy to achieve above shared outcome. Kindly advise.

2 Comments

Hi Abdul,
I haven't done any image processing for a long time, but maybe these comments can help.
  1. Remove image noise (imguidedfilter).
  2. Black and white conversion (rgb2gray).
  3. Convert to binary (imbinarize).
  4. Remove all elements smaller than a certain number of pixels (bwareaopen).
  5. Obtain the center of each line (regionprops).
If you know the pixel relation you can obtain also the values in micrometer, for example.
Best,
Alberto
thanks, I will try this sequence.

Sign in to comment.

 Accepted Answer

Another way is to get two images, one of all the vertical lines and one of all the horizontal lines. Use imopen() with the proper structuring element - either a vertical or horizontal rectangle.
Then threshold and get the centerlines with bwskel()
Then get a list of (x,y) for each line.
Then compare every vertical line with every horizontal line to find the distance that is min. This is where they cross. You can either use pdist2() or use a loop with sqrt(). This will give you the (x,y) intersection point for every line.
After that it's just some looping and bookkeeping to get the distances between adjacent points.
Again, if you can't figure it out, let me know.

7 Comments

Thank you, I will try both methodologies.
OK, here's about 95% of this approach. I assume you can find the distances between the square corners from this. Try meanXSeparation = mean(diff(x)) for the correct x, like all the x for one particular line.
% 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 = 22;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
folder = pwd;
baseFileName = 'grid1.png';
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
rgbImage = 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(rgbImage)
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 = rgbImage(:, :, 3);
else
grayImage = rgbImage;
end
% Get rid of faint grid lines with gray levels less than 31.
gridLines = grayImage <= 31;
grayImage(gridLines) = 0;
% first 11 rows and last 11 columns have junk in them. Erase those regions.
grayImage(1:11, :) = 0;
grayImage(:, end-10:end) = 0;
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 3, 1);
imshow(grayImage);
impixelinfo;
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Maximize window.
g = gcf;
g.WindowState = 'maximized';
drawnow;
% Display histogram.
subplot(2, 3, 2);
histogram(grayImage);
grid on;
drawnow;
title('Histogram of Image', 'FontSize', fontSize, 'Interpreter', 'None');
se = ones(1, 35);
grayImageH = imopen(grayImage, se);
% Display mask image.
subplot(2, 3, 3);
imshow(grayImageH, []);
hold on;
impixelinfo;
axis('on', 'image');
drawnow;
title('Mask, a Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
%--------------------------------------------------------------------------------------------------------
% Binarize the image to get a mask.
lowThreshold = 32;
highThreshold = intmax(class(grayImage));
% threshold(lowThreshold, highThreshold, grayImage);
mask = grayImage >= lowThreshold & grayImage <= highThreshold;
% Put red threshold line on histogram so they know where it was thresholded at.
xline(lowThreshold, 'Color', 'r', 'LineWidth', 2)
% Delete blobs touching border.
mask = imclearborder(mask);
% Get areas
props = regionprops(mask, 'Area');
allAreas = sort([props.Area])
mask = ~bwareaopen(~mask, 10000);
% Close up some little bays
mask = imclose(mask, true(5));
% Need to fill holes again since the openings were closed.
mask = ~bwareaopen(~mask, 10000);
% Take only the largest blob which will be the grid.
mask = bwareafilt(mask, 1);
% Display mask image.
subplot(2, 3, 3);
imshow(mask);
hold on;
impixelinfo;
axis('on', 'image');
drawnow;
title('Mask, a Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Get horizontal bars
barsH = medfilt2(mask, [1, 115]);
% There are some small blobs remaining. Get rid of blobs less than 10000 pixels.
props = regionprops(barsH, 'Area', 'PixelList'); % find out area of everything in the image at this point.
allAreas = sort([props.Area])
barsH = bwareaopen(barsH, 10000);
props = regionprops(barsH, 'Area', 'PixelList'); % find out area of everything in the image at this point.
allAreas = sort([props.Area])
% Display mask image.
subplot(2, 3, 4);
imshow(barsH);
hold on;
impixelinfo;
axis('on', 'image');
drawnow;
numLinesH = length(props);
caption = sprintf('%d Horizontal Bars', numLinesH);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
% Fit lines
hold on;
for k = 1 : numLinesH
x = props(k).PixelList(:, 1);
y = props(k).PixelList(:, 2);
coefficientsH{k} = polyfit(x, y, 2);
xFitH{k} = 1 : columns;
yFitH{k} = polyval(coefficientsH{k}, xFitH{k});
plot(xFitH{k}, yFitH{k}, 'r-', 'LineWidth', 2);
end
%=======================================================================================================
% Get vertical bars
barsV = medfilt2(mask, [115, 1]);
% There are some small blobs remaining. Get rid of blobs less than 10000 pixels.
props = regionprops(barsV, 'Area', 'PixelList'); % find out area of everything in the image at this point.
allAreas = sort([props.Area])
barsV = bwareaopen(barsV, 10000);
props = regionprops(barsV, 'Area', 'PixelList'); % find out area of everything in the image at this point.
allAreas = sort([props.Area])
% Display mask image.
subplot(2, 3, 5);
imshow(barsV);
hold on;
impixelinfo;
axis('on', 'image');
drawnow;
numLinesV = length(props);
caption = sprintf('%d Vertical Bars', numLinesV);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
% Fit lines
hold on;
for k = 1 : numLinesV
x = props(k).PixelList(:, 2);
y = props(k).PixelList(:, 1);
coefficientsV{k} = polyfit(x, y, 2);
xFitV{k} = 1 : rows;
yFitV{k} = polyval(coefficientsV{k}, xFitV{k});
% Swap them
[xFitV{k}, yFitV{k}] = deal(yFitV{k}, xFitV{k});
plot(xFitV{k}, yFitV{k}, 'r-', 'LineWidth', 2);
end
% Now for each horizontal bar, find the indexes where the lines cross (are closest).
subplot(2, 3, 6);
imshow(zeros(rows, columns, 'uint8')); % Display image.
hold on;
axis('on', 'image')
XCrossings = zeros(numLinesH, numLinesV);
YCrossings = zeros(numLinesH, numLinesV);
for k1 = 1 : numLinesH
fprintf('Finding where vertical lines cross horizontal line #%d.\n', k1);
xyH = [xFitH{k1}', yFitH{k1}'];
plot(xyH(:, 1), xyH(:, 2), 'r-', 'LineWidth', 2); % Plot horizontal line.
for k2 = 1 : numLinesV
xyV = [xFitV{k2}', yFitV{k2}'];
plot(xyV(:, 1), xyV(:, 2), 'r-', 'LineWidth', 2); % Plot horizontal line.
% Find distances between all points in vertical line from all points in horizontal line.
distances = pdist2(xyH, xyV);
minDistance = min(distances(distances > 0));
% Get indexes where the distance is min. Each line will have its own index.
[minRowH, minRowV] = find(distances == minDistance);
% Get the average.
xCrossing = mean([xyH(minRowH, 1), xyV(minRowV, 1)]);
yCrossing = mean([xyH(minRowH, 2), xyV(minRowV, 2)]);
XCrossings(k1, k2) = xCrossing;
YCrossings(k1, k2) = yCrossing;
% Plot a cyan spot at all the crossings.
plot(XCrossings(k1, k2), YCrossings(k1, k2), 'c.', 'MarkerSize', 20);
drawnow;
end
end
% Plot a cyan spot at all the crossings.
plot(XCrossings(:), YCrossings(:), 'c.', 'MarkerSize', 20);
title('Crossings Found', 'FontSize', fontSize);
@Image Analyst Thank you for this assistance and effort. I apologose for late response. I will try it, in case of any confusion I will share with you.
Regards
I'll be traveling for the next 4 days and may not respond until Saturday.
@Image Analyst thank you for this script. It benifited me alot in learning different combinations and functions. However, I tried alot for the last part but unfortunatley, I am unable to apply "meanXSeparation = mean(diff(x))" as you advised. Kindly if you can assist me in this part as well.
Why not? Is it still a problem? Can you run my code without error? If so, then attach your code.
@Image Analyst, the code is running perfect. Thank you for assistance.

Sign in to comment.

More Answers (1)

What I'd do is what I actually do in a very similar situation, though I'm looking for 5 points on the perimeter not 5. Here is the algorithm I think you can use
  1. binarize the image to find dark rectangles mask = imbinarize();
  2. call mask = bwareafilt(mask, [smallest, largest]) to get rid of small blobs and the super large one touching the border and get ONLY the valid squares.
  3. call imfill(mask, 'holes');
  4. Find centroid with props = regionprops(mask, 'Centroid', 'Image')
  5. Loop over all blobs and for each blob, props(k).Image, find boundaries with bwtraceboundary. Start on the left middle edge so you have a known starting point.
  6. Find distance of all boundary points to that blob's centroid and plot them. distances = sqrt((xCentroid-x)^2+(yCentroid2-y)^2)
  7. Find peaks with findpeaks(distances, .....). Specify the MinPeakDistance as half the approximate width of the square. If there are more than 4 peaks found, take the 4 with the highest prominence value. This gives you the index of the corners in the boundary coordinates. You'll have 1 is the upper left, 2 = upper right, 3 = lower right, and 4 = lower left.
  8. Compute distances like d12 = sqrt((x2-x1)^2+(y2-y1)^2), and similar for d23, d34, and d41. Stored the distances for each blob.
If you can't code it up from the pseudocode I've given so far, then let me know and I'll finish it.

Categories

Find more on Deep Learning Toolbox in Help Center and File Exchange

Products

Release

R2022a

Community Treasure Hunt

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

Start Hunting!