How to measure length and angle of (nearly) linear shapes in a binary image?

2 views (last 30 days)
Hello. I have the image below that contains multiple cross cutting lines and I want to i) measure the length of each individual line and ii) the angle of each individual line. The lines are not perfectly linear, so task iii) would be to try and figure out a way to approximate a linearity from the lines.
I have tried using regionprops (see below - sorry for any novice-based coding inelegance) but it only gives me one angle at the centre of the image. I assume it has something to do with the thickness of the lines, or the fact that the lines are cutting each other.
Any guidance on the issues with regionprops, or any alternative ways of doing this would be greatly valued!
fname01 = 'Angle_Test';
[grayImage,map] = imread([fname01, '.png']);
[rows, columns, numberOfColorChannels] = size(grayImage);
if numberOfColorChannels > 1
grayImage = grayImage(:, :, 1);
end
for i=1:100
for j =1:100
if grayImage(i,j) == 0;
grayImage(i,j) = 1;
end
end
end
for i=1:100
for j =1:100
if grayImage(i,j) == 255;
grayImage(i,j) = 0;
end
end
end
props = regionprops(grayImage, 'Orientation','Centroid');
figure(1)
imagesc(grayImage)
allOrientations = [props.Orientation]
hold on;
% Plot crosses over centroid.
for k = 1 : length(props)
x = props(k).Centroid(1);
y = props(k).Centroid(2);
plot(x, y, 'r+', 'MarkerSize', 30, 'LineWidth', 2);
caption = sprintf(' Angle = %.3f', props(k).Orientation);
text(x, y, caption, 'Color', 'r', 'FontSize', 18, 'FontWeight', 'bold');
end

Accepted Answer

Morgan
Morgan on 24 Jan 2024
Edited: Morgan on 24 Jan 2024
Check out the [BW,threshOut,Gx,Gy] = edge(grayImage). It returns the x- (Gx) and y-gradients (Gy) of every edge. The normal vectors and at every "edge" would be
ang = atan2(Gy(BW(:)),Gx(BW(:)));
nx = cos(ang);
ny = sin(ang);
If I were you, I'd break the problem down even further than you've described in your tasks into easier to solve tasks. Start with a single line of any length placed in any orientation. For every normal vector (i), calculate the angle between it and every other normal vector (j) via
You should get something that looks like
In the case of only one line, you should get the same number for each excluding the main diagonal. The angle of your line is theta = atan2(nyi,nxi) where nxi and nyi are the normal vectors at any of previously calculated. The length of your line is
L = sum(ang == theta)*resolution;
I'd set resolution to the geometric mean of your grid's x- and y-resolution but I'm sure there are better choices depending on the specific nature of your problem.
Then add a second line to grayImage! See how your matrix changes... You should get two unique numbers now barring some numerical noise. In the case of M lines, you should get M unique angles. Hint: Use unique() on the upper triangular matrix of .
My last tip is to visualize everything! You can use imagesc() to visualize and grayImage, quiver() to visualize the normal vectors, etc.

More Answers (0)

Tags

Products


Release

R2019a

Community Treasure Hunt

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

Start Hunting!