我想检测具有特定角度/方向的边缘。
从SO中的帖子改编,我已经想出使用OpenCV幅度,相位和Sobel函数来滤除不需要的边缘点。然后使用幅度图像(以相位图像作为条件)输出边缘点。
但是,结果与Canny边缘函数不相似。滤除不需要的角度的边缘是好的,但是检测到的边缘是点的斑点,而不是细线边缘
在使用findContours之后,也会绘制出左边缘图像,但这几乎没有帮助
1)还应该添加什么来模仿Canny处理?
2)至于定向边缘检测的目的,这种方法比使用除典型Sobel之外的定向核更稳健吗?
谢谢!
编辑01:
忘了把我的代码link
答案 0 :(得分:1)
1) 由于沿着邻居的非最大值抑制,Canny边缘检测器产生薄边缘。 为了模仿它,您需要选择沿该方向具有最大边缘响应的边缘像素。因此可以通过这种方式防止积分。
正如您可能猜到的那样,网格中较弱的图像可以通过您定义的阈值来抑制。
2)我无法给出一个明确的答案。对于给出的天使,内核可能受限于 离散化。因此,对于许多不同的角度,这种方法“应该”更好。
答案 1 :(得分:1)
或者,您可以尝试lsd,(http://www.ipol.im/pub/art/2012/gjmr-lsd/)。它将线路输出为两个点对,因此也可以进行方向滤波。
还有另一个线段实现@ http://sourceforge.net/projects/lswms/虽然上面的lsd链接有更好的结果
如果您想要单个像素边缘,则需要进行骨架化/细化
在编译时将lsd.c
重命名为lsd.cpp
。我使用了网址中附带的1.6版本。代码和结果如下。您可以调整阈值以抑制小段。
#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);
}