Orientational Canny Edge Detection

2019-01-26 22:16发布

问题:

I want to detect edges using Canny method. In the end I want two edge maps: 1 for horizontal 1 for vertical direction.

In MATLAB this can be achieved by using Sobel or Prewitt operators with an extra direction argument, but for Canny we do not have this option.

E = edge(I,'Sobel','horizontal')

Any idea how to extract both horizontal and vertical edges, separately, by using Canny?

回答1:

There is no way using the built in edge function. However, Canny edge detection uses the angles from the Sobel Operator. It is very easy to reproduce these values.

  1. Start with an image, I'll use a built in demo image.

    A = im2double(rgb2gray(imread('peppers.png')));
    
  2. Get the Canny edges

    A_canny = edge(A, 'Canny');
    
  3. Sobel Operator -- We can't use the built in implementation (edge(A_filter, 'Sobel')), because we want the edge angles, not just the edge locations, so we implement our own operator.

    a. Gaussian filter. This is a preprocessing step for Canny, so we should probably reproduce it here

    A_filter = imgaussfilt(A);
    

    b. Convolution to find oriented gradients

    %These filters measure the difference in values between vertically or horizontally adjacent pixels. 
    %Effectively, this finds vertical and horizontal gradients.
    vertical_filter = [-1 0 1; -2 0 2; -1 0 1];
    horizontal_filter = [-1 -2 -1; 0 0 0; 1 2 1];
    A_vertical = conv2(A_filter, vertical_filter, 'same');
    A_horizontal = conv2(A_filter, horizontal_filter, 'same');
    

    c. Calculate the angles

    A_angle = arctan(A_vertical./A_horizontal);
    
  4. Get the angle values at the edge locations

    A_canny_angles = nan(size(A));
    A_canny_angles(A_canny) = A_angle(A_canny);
    
  5. Choose the angles that you are interested in

    angle_tolerance = 22.5/180*pi;
    target_angle = 0;
    A_target_angle = A_canny_angles >= target_angle*pi/180 - angle_tolerance & ...
        A_canny_angles<= target_angle*pi/180 + angle_tolerance;
    

So if I'm looking for horizontal lines, my target angle would be zero. The image below illustrates steps 1, 2, 4 and 5. The final result of the extracted horizontal lines is shown in the bottom right. You can see that they are not exactly horizontal because I used such a large angle tolerance window. This is a tunable parameter depending on how exactly you want to hit your target angle.