holistic
holistic

Reputation: 103

Finding vertical and diagonal lines in binary matrix in Matlab

I have a binary matrix, say:

matrix=double(rand(100,100)>0.7);

I want to find all "diagonal lines" of 1's (from bottom left to top right) of length 2 or more elements in this matrix and set all other 1's to 0, so that I get another matrix with only those diagonal lines.

I want to do the same for vertical lines.

Is there a simple way to do this?

Upvotes: 0

Views: 751

Answers (2)

Suever
Suever

Reputation: 65430

You can use 2D convolution combined with some fancy kernels to detect this. The basic idea is to craft a kernel that looks like the feature you're trying to detect.

First of all, there are two types of diagonals to detect:

  1. top left to bottom right
  2. top right to bottom left.

We can design a kernel to detect that first type:

kernel = [1 0 0;
          0 1 0;
          0 0 1];

This is simply the identity matrix (eye(3)), if we convole this with your input.

conv2(matrix, eye(3), 'same');

If we do this to the identity matrix as a test, we can see the result of the convolution

enter image description here

You can clearly see that the pixels that are part of the diagonal have values > 1. We can then convert this to a binary matrix indicating whether a pixel is along the diagonal. You also want to ensure that the current pixel is also 1.

is_top_left_to_bottom_right = conv2(matrix, eye(3), 'same') > 1 & logical(matrix);

In a similar way, we can flip the kernel to detect diagonals going the other way.

is_top_right_to_bottom_left = conv2(matrix, fliplr(eye(3)), 'same') > 1 & logical(matrix);

Then you can look at either independently or join them with a logical or

is_diagonal = is_top_left_to_bottom_right | is_top_right_to_bottom_left;

For horizontal and vertical lines you can use the following kernels in a similar way as the above (remember that I said at the beginning that you want the kernel to look like the feature you're trying to detect!).

horizontal = [0 0 0
              1 1 1
              0 0 0];

vertical = [0 1 0 
            0 1 0
            0 1 0];

Upvotes: 1

Daniel
Daniel

Reputation: 36710

You can use conv2 to detect the lines:

% your data
M=double(rand(100,100)>0.7);
%length you want to detect
n=2;
kernel=eye(n);
%detect diagonal ones from top left to bottom right
lines=conv2(M,eye(n),'same')==sum(kernel(:));

For diagonals going the other direction, use kernel=fliplr(eye(n)); instead of kernel=eye(n);

For vertical and horizontal lines use kernel=ones(n,1); or kernel=ones(1,n);

The kernels are matrices containing what you want to detect:

>> kernel=eye(n)

kernel =

     1     0
     0     1

>> kernel=fliplr(eye(n))

kernel =

     0     1
     1     0

>> kernel=ones(n,1)

kernel =

     1
     1

>> kernel=ones(1,n)

kernel =

     1     1

Note that for the second diagonal the marked position might be a bit confusing, because convolution works with rectangles. Inputting

[0 0 0;
0 1 0;
1 0 0]

It will return:

[0 0 0;
1 0 0;
0 0 0]

Marking the top left of the rectangles where a diagonal was found. Now having code to identify the diagonals, again convolution can be used to create the intended matrix:

M=(conv2(double(conv2(M,kernel,'valid')==sum(kernel(:))),kernel,'full'))>0

Upvotes: 2

Related Questions