图像中的线检测

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图像中的线检测相关的知识,希望对你有一定的参考价值。

我是图像处理的新手,我试图用这个代码检测垂直线 -

image=imread('benzene.jpg');  
BW = im2bw(image);
w1=[-1 2 -1 ; -1 2 -1 ; -1 2 -1];
g=(imfilter(double(BW),w1));
g=abs(g);
T=max(g(:));
g=g>=T;
imshow(g);

这是我的形象 -

这是我在执行操作后得到的 -

所以我的问题是为什么我得到这个输出?如果垂直双键被算作2条不同的垂直线,那么有10条垂直线。如果我想要获得水平,垂直,45和-45所有线条,我该怎么办?使用所有4个掩码来获得一个输出?

答案

我有一个简单的建议是检测渐变并确定边缘点的方向。请记住,方向是垂直于边缘的方向。因此,如果要查找垂直线,垂直于垂直线的方向是水平的,相对于笛卡尔平面为180度或-180度。因此,对于检测到的边缘点的每个方向,如果方向是-180度或180度,则将该位置的输出设置为true,否则为false。要检测渐变方向,请使用图像处理工具箱中的imgradient。我假设这是可用的,因为你已经使用了imreadim2bw,它们都是该工具箱的一部分:

im = imread('http://i.stack.imgur.com/bdNOt.png');
tol = 5;
[~,ang] = imgradient(im);
out = (ang >= 180 - tol | ang <= -180 + tol);
imshow(out);

该代码使用一个名为tol的变量来定义您想要检测的角度的公差,以考虑看起来垂直的噪声或边缘,但是当计算角度时,它可能看起来不是。基本上,我们正在寻找角度在180度或-180度之内的任何点。

这就是我们得到的:

作为后处理的一种方法,您可以使用bwareaopen过滤掉区域低于一定量的像素区域。利用垂直线比其他像素具有更大面积的事实,您可以执行以下操作:

out_filter = bwareaopen(out, 50);

我们得到:


现在,如果要检测水平线,则应找到-90度或90度的渐变方向。这是有道理的,因为那些水平的线,垂直于水平线的方向确实是垂直的,并且是-90度或90度。如果你想要斜线,如果你想要左倾斜线,寻找45度或-135度和右倾斜线的角度,-45度或135度。我会让你弄清楚为什么这些角度确实代表了那些线条。

你提供的图像中没有任何水平线,所以我只想寻找斜线:

Left leaning lines

注意:由于量化错误,我不得不增加容差。

im = imread('http://i.stack.imgur.com/bdNOt.png');
tol = 20;
[~,ang] = imgradient(im);
out = (ang >= 45 - tol & ang <= 45 + tol) | (ang >= -135 - tol & ang <= -135 + tol);
out_filter = bwareaopen(out, 50);
imshow(out_filter);

Right leaning lines:

此外还必须增加容差:

im = imread('http://i.stack.imgur.com/bdNOt.png');
tol = 20;
[~,ang] = imgradient(im);
out = (ang >= 135 - tol & ang <= 135 + tol) | (ang >= -45 - tol & ang <= -45 + tol);
out_filter = bwareaopen(out, 50);
imshow(out_filter);

另一答案

另一种方法是使用描绘债券的所有线具有相同的纵横比和面积的事实。在对图像进行过滤之后,我们可以查看方向或构成它们的索引列表,以检测它们是否是垂直的或诸如此类的。所有这一切都可以使用regionprops完成。

image=rgb2gray(imread('benzene.png'));  
d=abs(255-image); % inverse the image
d=im2bw(d);
stat=regionprops(d,'Area', 'Orientation','PixelIdxList'); 
areas=[stat.Area];
hist(areas)

检查直方图显示线的切割位置,线的面积小于字母,并且它们应具有大致相同的面积。所以我切割1000像素以下的区域:

idx=find(areas<1000);
angs=round([stat(idx).Orientation]);

现在你可以使用angsidx来获得你想要的任何类型的线。例如,让我们绘制30度线:

d2=zeros(size(d));
d2(vertcat(stat(idx(angs==30)).PixelIdxList))=1;
imagesc(d2)

请注意,当我开始回答这个问题时,我拍摄的图像是苯.png文件。现在我意识到你提供了一个与原始图像不同的图像,这样描绘债券的线条并不是分开的,而是你有“戒指”。我稍后会看到,如果你想要我,我也可以解决这个问题。

编辑:

要找到新图像的相关线条,在哪里有环,线条的唯一区别是,它们是直线“线”而不是弯曲。所以我诉诸于心爱的Hough transform来接他们:

image=imread('http://i.stack.imgur.com/bdNOt.png');
d=abs(1-image); % inverse the image
BW=im2bw(d);
BW = bwmorph(BW,'skel',1);
[H, T, R] = hough(BW,'Theta',-90:10:80);
P = houghpeaks(H, 100,'NHoodSize',[3 3],'threshold',1);
lines = houghlines(BW, T, R, P, 'FillGap',5, 'MinLength', 35);

让我们获得检测到的线条的角度:

angs=round([lines.theta]);

你会看到angs会产生0度,-60度或60度的值。

假设您只想绘制0度的那些:

p1=vertcat(lines(angs==0).point1);
p2=vertcat(lines(angs==0).point2);

imshow(BW, 'InitialMag',200, 'Border','tight'), hold on

for k = 1:size(p1,1)
   line([p1(k,1) p2(k,1)],[p1(k,2) p2(k,2)], 'LineWidth',4,...
   'Color',[1 0 0]); hold on
end
hold off

另一答案

我仍然在做这件事。但到现在为止我已经得到了这个。我没有使用过滤器,而是使用了不同的过滤器。

我使用了你提供的第一张图片。过滤器在这里描述:image_filters

image=imread('benzene.png');  
BW = im2bw(image);
w1=(1/3)*[1 0 -1;1 0 -1;1 0 -1];
g=(imfilter(double(BW),w1));
g(g<1)=0;
imshow(g);

我得到的输出是这样的:你可以看到结果还没有完成。我建议你尝试两件事:使用形态侵蚀算子去除小元素。您也可以使用连接的组件来执行此操作。

在此期间尝试做我的建议。如果我得到答案,我会更新它。

以上是关于图像中的线检测的主要内容,如果未能解决你的问题,请参考以下文章

图像中的线检测——hough变换

Canny 边缘检测未检测到 100% 水平/未旋转的线

从图像中提取稳健的线

在 Python 多处理进程中运行较慢的 OpenCV 代码片段

如何使用模块化代码片段中的LeakCanary检测内存泄漏?

使用 OpenCV 检测停车位