0
votes

I would like to detect edge that has certain angle/orientation.

Adapting from a post in SO, I've figured out to use OpenCV magnitude, phase and Sobel functions to filter out unwanted edge points. Then use the magnitude image (with phase image as condition) to output the edge points.

However, the results is not similar to Canny edge function. It's good that the edges with unwanted angles are filtered out but detected edges are blobs of points, not thin line edge

enter image description here

the left edge image is also plotted out after findContours is used, but this barely helps out

1) what else should be added to mimic Canny processing?

2) As for the purpose of directional edge detection, is this approach more robust than using a directional kernel other than typical Sobel ones?

Thank you!

Edit 01:

forgot to put my code link

2
The accepted answer is right, but probably outdated. I don't know when it was added, but now there is LSD and Hough Lines detection methods in OpenCV. Also, for more information, refer to:stackoverflow.com/questions/43050075/…Gustavo Kaneto

2 Answers

1
votes

alternatively, you can try lsd,(http://www.ipol.im/pub/art/2012/gjmr-lsd/). it outputs lines as two point pairs so directional filtering is also possible.

there's also another line segment implementation @ http://sourceforge.net/projects/lswms/ though the lsd link above has better results

if you want a single pixel edge, you would need to do skeletonization/thinning

edit

rename the lsd.c into lsd.cpp when you are compiling. i used version 1.6 attached in the url. code and results below. you can tweak the thresholds to suppress the small segments as well.

#include "opencv2/opencv.hpp"
using namespace cv;
#include "lsd.h"
void lsd_call(Mat& im)
{
    Mat gray;
    cvtColor(im,gray,CV_BGR2GRAY);
    Mat imgdouble;
    gray.convertTo(imgdouble,CV_64FC1);
    double * image;
    double * out;
    int x,y,i,j,n;
    out = lsd(&n,(double*)imgdouble.data,imgdouble.cols,imgdouble.rows);
    Mat lines = im.clone();
    Mat lines_binary = Mat::zeros(gray.size(),CV_8UC1);
    for(i=0;i<n;i++)
    {
        double x1,y1,x2,y2,w;
        x1 = out[7*i+0];
        y1 = out[7*i+1];
        x2 = out[7*i+2];
        y2 = out[7*i+3];
        w = out[7*i+4];
        double length = sqrt(pow(x1-x2,2)+pow(y1-y2,2));
        double angle =  atan2(y2 - y1, x2 - x1) * 180 / CV_PI;

        if(angle<180 && angle>90)
        {
            line(lines,Point2d(out[7*i+0],out[7*i+1]),Point2d(out[7*i+2],out[7*i+3]),Scalar    (0,0,255));
            line(lines_binary,Point2d(out[7*i+0],out[7*i+1]),Point2d(out[7*i+2],out[7*i+3])    ,Scalar(255));
        }
        if(length>75)
        {
            //line(todraw,Point2d(out[7*i+0],out[7*i+1]),Point2d(out[7*i+2],out[7*i+3]),    Scalar(0,0,255),out[7*i+4]);
        }
    }
    imshow("lines",lines);
    imshow("lines_binary",lines_binary);
    imwrite("c:/data/lines.jpg",lines);
    imwrite("c:/data/linesbinary.jpg",lines_binary);
    free( (void *) out );

}
int main(int argc,char** argv )
{
    Mat im = imread("c:/data/lines.png");
    lsd_call(im);
    waitKey(0);
}

lines overlaylines binary

1
votes

1) Canny edge detector produces thin edges because of non-maxima supression along the neighbours. In order to mimic that, you need to choose edge pixels with maximimum edge response along that direction. So blobs of points can be prevented this way.

As you can probably guess, the weaker images in the grid can be suppressed with threshold defined by you.

2) I can't give a definite answer to that sadly. For the angel given, the kernels might be limited by discretization. So for many different angles, this approach 'should' be better.