图像中的线检测

Line detection in image

我是图像处理的新手,我正在尝试使用此代码检测垂直线-

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 条垂直线 lines.Also 如果我想获得水平、垂直、45 和 -45 怎么办所有的线,我怎样才能使用所有的 4 个掩码来获得一个单一的输出?

我还在做这件事。但直到现在我已经明白了。我没有使用你的过滤器,而是使用了一个不同的过滤器。

我使用了您提供的第一张图片。过滤器在此处描述: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);

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

在此期间尝试按照我的建议进行操作。如果我得到答案,我会更新它。

我有一个简单的建议是检测梯度并确定边缘点的方向。请记住,方向是与边缘 垂直 的方向。所以,如果要找竖线,垂直于竖线的方向就是水平方向,相对于笛卡尔平面要么是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 度以内的任何点。

这是我们得到的:

作为 post 处理的一种方式,您可以使用 bwareaopen 过滤掉面积低于一定数量的像素区域。利用垂直线的面积比其他像素大的事实,你可以这样做:

out_filter = bwareaopen(out, 50);

我们得到:


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

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

左倾线

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

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);

右倾线:

这里也必须增加公差:

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)

请注意,在我开始回答这个问题时,我拍摄的图像是 benzene.png 文件。现在我意识到您提供的图像与原始图像不同,因此描绘债券的线条不是分开的,而是 "rings"。如果您希望我解决这个问题,我稍后再看。

编辑:

要找到新图像的相关线,在你有环的地方,这些线的唯一区别是,嗯,它们是直的 "lines" 而不是弯曲的。所以我求助于心爱的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