【问题标题】:Line detection in image图像中的线检测
【发布时间】:2015-09-05 05:28:44
【问题描述】:

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

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 个掩码来获得一个输出?

【问题讨论】:

  • 你能给这张图片的在线链接吗?我在网上找不到它
  • 我已经编辑了我的问题。我理解我的错误,但现在我又得到了意外的输出。
  • @roni 你可以从这里保存这张图片,因为我现在没有图片链接。
  • 问题出在你的过滤器上,当然。阅读一些基本过滤器以了解情况:en.wikipedia.org/wiki/Prewitt_operatoren.wikipedia.org/wiki/Sobel_operator

标签: image matlab image-processing computer-vision edge-detection


【解决方案1】:

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

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

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

同时尝试按照我的建议去做。如果我得到答案,我会更新它。

【讨论】:

  • 除了形态学运算之外,还有一种更简单的方法来检测这条直线(在过滤之后)。只需一个接一个(例如imlabel)并计算每个高度的宽度。如果它是恒定的,那么它是一条直线,否则它是你想要避免的一些噪音/
  • 我更多地考虑霍夫变换。但我无法应用它
【解决方案2】:

我有一个简单的建议是检测梯度并确定边缘点的方向。请记住,方向是与边缘垂直的方向。因此,如果要找到垂直线,垂直于垂直线的方向是水平的,即相对于笛卡尔平面的 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 度。我会让你弄清楚为什么这些角度确实代表了这些线条。

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

左倾线

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

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

【讨论】:

  • out=bwareaopen(out,50); 跟进(可能需要稍微调整阈值)以删除与字母相关的行。
  • @Jonas - 你读懂了我的想法......我实际上只是这样做了哈哈。你和我选择了完全相同的阈值也很有趣。
  • 很好的答案自己想不通!
  • 水平将是 0 或 90。倾斜应该是 +/- 45 和 +/- 135。我会更新我的帖子,向您展示更多具有相同图像的线条。
  • @Noober - 完成。看看吧。
【解决方案3】:

另一种方法是利用所有描绘键的线条都具有相同的纵横比和面积这一事实。在过滤图像后只留下键,我们可以查看方向或组成它们的索引列表,以检测它们是垂直的还是其他的。所有这些都可以使用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)

请注意,在我开始回答这个问题时,我拍摄的图像是 benzo.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

【讨论】:

  • 非常感谢。但是你是怎么决定只剪不到 1000 块的呢?
  • 另外我该如何使用anglesidx?你能举个例子吗?
  • 非常感谢。实际上是的,我确实有戒指要处理。
  • 我也添加了能接听响铃的版本
  • 非常感谢。我接受的答案已经足够好,但我希望找到一些替代方法来获得相同的结果。再次感谢这真的很有帮助。
猜你喜欢
  • 2010-10-15
  • 1970-01-01
  • 2020-09-05
  • 2012-11-25
  • 1970-01-01
  • 1970-01-01
  • 2020-03-09
  • 2013-10-31
  • 2013-05-15
相关资源
最近更新 更多