How to find intersection coordinates of node points in truss image?

Hello, I would like to know the way to find coordinate points (x,y) of nodes in truss image. I give an example of image. In that image, I will get only six edge points and I will exclude two crossed points in the middle. How can I find the coordinate points in that figure?

 Accepted Answer

If you are always dealing with regular trusses, your best option may be to detect vertical and horizontal edges by summation over dimensions 1 and 2:
img = im2bw(imread('TrussExt1.png')) ;
subplot(1,2,1) ; plot(sum(img,1)) ; grid('on') ; title('Sum over rows') ;
subplot(1,2,2) ; plot(sum(img,2)) ; grid('on') ; title('Sum over columns') ;
Getting the relevant nodes coordinates hence just means getting these mins:
>> c = find(sum(img, 1) < size(img, 1)/2)
c =
21 22 23 183 184 185 346 347 348 508 509 510 671 672 673
we see that, as the horizontal and vertical lines are 3 pixels wide, we get three close numbers per min, and we can take the "middle ones" as follows:
>> c(2:3:end)
ans =
22 184 347 509 672
Putting all that together we get:
img = im2bw(imread('TrussExt1.png')) ;
c = find(sum(img, 1) < size(img, 1)/2) ;
c = c(2:3:end) ;
r = find(sum(img, 2) < size(img, 2)/2) ;
r = r(2:3:end) ;
[R, C] = meshgrid(r, c) ;
imshow(img) ;
hold('on') ;
plot( C(:), R(:), 'rx', 'MarkerSize', 10, 'LineWidth', 3 ) ;
If you are not always dealing with regular trusses, your best option may be to detect the diagonal cross nodes and to build a grid based on them, using the position of the outer boundaries found by taking the first and last mins using the approach developed above.
Here is an example, where we spot the nodes that you don't want to get:
img = im2bw(imread('TrussExt2.png')) ;
ker = [0,0,0,1,1,1,1,1,1,1,0,0,0; ...
1,1,0,0,0,1,1,1,0,0,0,0,1; ...
1,1,1,0,0,0,1,0,0,0,1,1,1; ...
1,1,1,1,0,0,0,0,0,1,1,1,1; ...
1,1,1,1,0,0,0,0,0,1,1,1,1; ...
1,1,1,0,0,0,0,0,0,0,1,1,1; ...
1,1,0,0,0,1,1,1,0,0,0,1,1; ...
0,0,0,0,1,1,1,1,1,0,0,0,0] ;
ker = 10 * (1 - 2*ker) ; % {0,1} -> {10,-10}.
ker = rot90(ker, 2) ;
cv = conv2( 1-img, ker, 'same' ) ;
[r,c] = find(cv > 0.7*max(cv(:))) ;
figure() ;
imshow(img) ;
hold('on') ;
plot(c, r, 'ro', 'MarkerSize', 10, 'LineWidth', 3) ;
Applied to TrussExt2.png attached to my answer, we get:
which shows that it is working pretty well. Depending the quality of the image, we may have to filter/cluster the output of FIND, but in this case we don't. I'll stop here but with a little extra work, you can find the nodes of the "multi-scale" rectangular grid that corresponds to these "cells centers".
Another approach could consist in performing more shape-specific convolutions, in order to target the 6 or 7 possible geometries of interest. As the width of the non-diag. lines is 3 pixels, it could be done as follows:
img = im2bw(imread( 'truss.JPG')) ;
imshow(img) ;
hold('on') ;
np = 3 ; B = ones(np) ;
kernels = {[-B,-B,-B;-B, B, B;-B, B, B], ... % sym. lower right
[-B,-B,-B; B, B, B; B, B, B], ... % sym. lower middle
[-B,-B,-B; B, B,-B; B, B,-B]} ; % sym. lower left
kernels = [kernels, cellfun(@flipud, kernels, 'UniformOutput', false)] ;
nKer = numel(kernels) ;
colors = jet(nKer) ;
for kId = 1 : nKer
cv = conv2(1-2*img, kernels{kId}, 'same') ;
[r, c] = find(cv == max(cv(:))) ;
plot(c, r, 'x', 'Color', colors(kId,:), 'MarkerSize', 20, 'LineWidth', 3) ;
end
If you have many nodes of each type/shape though, you may need to set a tolerance ( cv >= tol*max(cv(:)) ) and aggregate close points (which brings us back to clustering).
Or, if you know the number of relevant points in advance, you can reduce you problem to a peak identification problem or a clustering problem:
img = im2bw(imread('truss.JPG')) ;
n = 3 ; B = ones( n ) ; ker = [B, 10*B, B; 10*B, 10*B, 10*B; B, 10*B, B]/(3*n)^2 ;
cv = conv2(1-img, ker, 'same') ;
surf(cv)
where you see that all straight lines and diagonal crosses are below the level of the 6 relevant nodes. I defined the weights of the blocks in the kernel for that purpose. The condition is that elements of the "high" blocks are greater than twice the value of elements of the "low" blocks, and elements of the "low" blocks must be positive (I picked 10 and 1 as weights of B to be on the safe side).

9 Comments

If we consider the coordinates of the left lower point as (0,0), how can we determine the data of other coordinate points that are detected?
This lower point must be detected, because the image has a white rim and you cannot consider pixel (1,1) (or any other corner pixel) as the origin of a system of axes. If the image was cropped on all sides and you knew in advance the number of rows and columns, you could of course find the column IDs of relevant nodes using a simple rounded linspace(1,size(img,2),nCols) and same for rows.
But if you need to detect a corner anyway, my first approach is likely to be the simplest way to process trusses with 3 pixels wide vertical and horizontal lines (which can easily be adapted to other line widths).
Have you considered inverting the image and calling conv2() or imfilter() to count the white strut pixels, then calling imregionalmax() to find peaks?
I have not, but I am happy to try whatever I can learn from you about image processing. I will give it a try. I tried your first approach though, but I couldn't get rid of the diagonals and their intersections.
I tried using CONV2/IMGREGIONALMAX but I can't seem to be able to find an appropriate kernel (that doesn't produce local maxima in diagonals):
I'm still now clear which intersection points he want. Any of them? Or only certain types/styles of intersections?
All nodes but the intersections of the diagonals, e.g.
He/she didn't come back however, so I don't think that it is worth spending a lot of your time finding alternatives.
Thank you so much. I have learnt a lot and my problem is solved from your answer.

Sign in to comment.

More Answers (1)

Call bwmorph(BW, 'skel', inf) followed by bwmorph(bw, 'branchpoints') followed by find(). See attached demo.

Asked:

on 29 Sep 2017

Commented:

on 10 Oct 2017

Community Treasure Hunt

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

Start Hunting!