matlab 图像中的自主接缝检测
Autonomous seam detection in Images on matlab
我正在尝试为自主焊接过程检测焊接图像中的接缝。
我想在原始图像中找到检测到的线(所需图像中的红线)的像素位置。
我使用了下面的代码,最后去除了图像中的噪声,得到了下面的结果。
clc,clear,clf;
im = imread('https://i.stack.imgur.com/UJcKA.png');
imshow(im);title('Original image'); pause(0.5);
sim = edge(im, 'sobel');
imshow(sim);title('after Sobel'); pause(0.5);
mask = im > 5;
se = strel('square', 5);
mask_s = imerode(mask, se);
mask(mask_s) = false;
mask = imdilate(mask, se);
sim(mask) = false;
imshow(sim);title('after mask');pause(0.5);
sim= medfilt2(sim);
imshow(sim);title('after noise removal')
遗憾的是图像中没有任何东西可以完美找到接缝。
如有任何帮助,我们将不胜感激。
Download原图。
您需要使您的滤波器对噪声更加鲁棒。这可以通过给它更大的支持来完成:
filter = [ones(2,9);zeros(1,9);-ones(2,9)];
msk = imerode(im > 0, ones(11)); % only object pixels, discarding BG
fim =imfilter(im,filter);
robust = bwmorph((fim>0.75).*msk,'skel',inf); % get only strong pixels
坚固的面具看起来像:
如你所见,接缝线检测的很好,我们只需要将它选为最大连通分量即可:
st = regionprops(bwlabel(robust,8), 'Area', 'PixelList');
[ma mxi] = max([st.Area]); % select the region with the largest area
现在我们可以将多边形(2 度)拟合到表面:
pp=polyfit(st(mxi).PixelList(:,1), st(mxi).PixelList(:,2), 2);
图片就在这里:
imshow(im, 'border','tight');hold on;
xx=1:size(im,2);plot(xx,polyval(pp,xx)+2,'r');
请注意 +2
Y 偏移由于过滤器宽度。
PS,
您可能会发现 相关。
Shai 给出了一个很好的答案,但我想添加更多关于为什么你的噪声过滤不起作用的上下文。
为什么中值过滤不起作用
Wikipedia 建议中值滤波在保留边缘的同时去除噪声,这就是您可能选择使用它的原因。但是,在您的情况下,它几乎肯定不会起作用,原因如下:
中值滤波在图像上滑动 window。在每个区域中,它用周围 window 的中值替换中心像素。 medfilt2
默认使用 3x3 window。让我们看看你的线附近的一个 3x3 块,
[212 157] 周围的 3x3 块看起来像这样
[0 0 0
1 1 1
0 0 0]
中值为0!因此,即使我们处于线段的中间,像素也会被过滤掉。
中值滤波的替代方法
Shai 的去噪方法会找到最大的连接像素组并忽略较小的像素组。如果您还想从图像中删除这些小的组,Matlab 提供了一个过滤器 bwareaopen
可以从二值图像中删除小对象。
例如,如果您更换线路
sim= medfilt2(sim);
和
sim= bwareaopen(sim, 4);
结果好多了
替代边缘检测器
最后一点,Shai 使用水平渐变过滤器来查找图像中的水平边缘。它很好用,因为你的边缘是水平的。如果你的边缘并不总是水平的,你可能想使用另一种边缘检测方法。在您的原始代码中,您使用 Sobel,但 Matlab 提供了许多选项,如果您调整它们的阈值,所有这些选项都会表现得更好。例如,在下图中,我使用四种不同的边缘检测器突出显示了您的代码(使用 bwareaopen 修改)选择的像素。
我正在尝试为自主焊接过程检测焊接图像中的接缝。
我使用了下面的代码,最后去除了图像中的噪声,得到了下面的结果。
clc,clear,clf;
im = imread('https://i.stack.imgur.com/UJcKA.png');
imshow(im);title('Original image'); pause(0.5);
sim = edge(im, 'sobel');
imshow(sim);title('after Sobel'); pause(0.5);
mask = im > 5;
se = strel('square', 5);
mask_s = imerode(mask, se);
mask(mask_s) = false;
mask = imdilate(mask, se);
sim(mask) = false;
imshow(sim);title('after mask');pause(0.5);
sim= medfilt2(sim);
imshow(sim);title('after noise removal')
遗憾的是图像中没有任何东西可以完美找到接缝。
如有任何帮助,我们将不胜感激。
Download原图。
您需要使您的滤波器对噪声更加鲁棒。这可以通过给它更大的支持来完成:
filter = [ones(2,9);zeros(1,9);-ones(2,9)];
msk = imerode(im > 0, ones(11)); % only object pixels, discarding BG
fim =imfilter(im,filter);
robust = bwmorph((fim>0.75).*msk,'skel',inf); % get only strong pixels
坚固的面具看起来像:
如你所见,接缝线检测的很好,我们只需要将它选为最大连通分量即可:
st = regionprops(bwlabel(robust,8), 'Area', 'PixelList');
[ma mxi] = max([st.Area]); % select the region with the largest area
现在我们可以将多边形(2 度)拟合到表面:
pp=polyfit(st(mxi).PixelList(:,1), st(mxi).PixelList(:,2), 2);
图片就在这里:
imshow(im, 'border','tight');hold on;
xx=1:size(im,2);plot(xx,polyval(pp,xx)+2,'r');
请注意 +2
Y 偏移由于过滤器宽度。
PS,
您可能会发现
Shai 给出了一个很好的答案,但我想添加更多关于为什么你的噪声过滤不起作用的上下文。
为什么中值过滤不起作用
Wikipedia 建议中值滤波在保留边缘的同时去除噪声,这就是您可能选择使用它的原因。但是,在您的情况下,它几乎肯定不会起作用,原因如下:
中值滤波在图像上滑动 window。在每个区域中,它用周围 window 的中值替换中心像素。 medfilt2
默认使用 3x3 window。让我们看看你的线附近的一个 3x3 块,
[212 157] 周围的 3x3 块看起来像这样
[0 0 0
1 1 1
0 0 0]
中值为0!因此,即使我们处于线段的中间,像素也会被过滤掉。
中值滤波的替代方法
Shai 的去噪方法会找到最大的连接像素组并忽略较小的像素组。如果您还想从图像中删除这些小的组,Matlab 提供了一个过滤器 bwareaopen
可以从二值图像中删除小对象。
例如,如果您更换线路
sim= medfilt2(sim);
和
sim= bwareaopen(sim, 4);
结果好多了
替代边缘检测器
最后一点,Shai 使用水平渐变过滤器来查找图像中的水平边缘。它很好用,因为你的边缘是水平的。如果你的边缘并不总是水平的,你可能想使用另一种边缘检测方法。在您的原始代码中,您使用 Sobel,但 Matlab 提供了许多选项,如果您调整它们的阈值,所有这些选项都会表现得更好。例如,在下图中,我使用四种不同的边缘检测器突出显示了您的代码(使用 bwareaopen 修改)选择的像素。