图像中的线检测

Noo*_*ber 9 matlab image image-processing computer-vision edge-detection

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

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);
Run Code Online (Sandbox Code Playgroud)

这是我的形象 -

在此输入图像描述

这是我在执行操作后得到的 - 在此输入图像描述

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

ray*_*ica 14

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

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

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

这就是我们得到的:

在此输入图像描述

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

out_filter = bwareaopen(out, 50);
Run Code Online (Sandbox Code Playgroud)

我们得到:

在此输入图像描述


现在,如果要检测水平线,则应找到-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);
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

右倾斜线:

此外还必须增加容差:

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);
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 用'out = bwareaopen(out,50);`(可能需要调整一点阈值)来删除与字母相关的行. (2认同)

bla*_*bla 7

另一种方法是使用描绘债券的所有线具有相同的纵横比和面积的事实.在对图像进行过滤之后,我们可以查看方向或构成它们的索引列表,以检测它们是否是垂直的或诸如此类的.所有这一切都可以使用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)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

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

idx=find(areas<1000);
angs=round([stat(idx).Orientation]);
Run Code Online (Sandbox Code Playgroud)

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

d2=zeros(size(d));
d2(vertcat(stat(idx(angs==30)).PixelIdxList))=1;
imagesc(d2)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

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

编辑:

为了找到新图像的相关线,你有环,这条线的唯一区别是,它们是直的"线"而不是弯曲的.所以我诉诸于心爱的霍夫变换来接他们:

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);
Run Code Online (Sandbox Code Playgroud)

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

angs=round([lines.theta]);
Run Code Online (Sandbox Code Playgroud)

你会看到这里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
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 只是古玩,为什么你接受的答案不够好? (2认同)