我是机械工程专业的学生,正在研究一个项目,以自动检测车间中存在的焊缝(焊缝是要焊接的边缘)。这给出了焊接中涉及的基本术语(http://i.imgur.com/Hfwjq0w.jpg)。
为了将焊件与其他物体分开,我拍摄了背景图像并减去了具有焊件的前景图像,仅对焊件进行了观察(http://i.imgur.com/v7yBWs1.jpg)。图像相减后,仍然存在减去背景的阴影,眩光和残余噪声。
由于我想自动识别没有焊件外边界的焊缝,我试图使用canny算法检测焊件图像中的边缘,并尝试使用bwareopen函数消除孤立的噪声。我已经以某种方式获得焊件和焊缝的近似边界。我使用的门限纯粹是试错法,因为不知道自动设置阈值来检测它们的方法。
我现在面临的问题是我无法指定一个明确的阈值,因为该算法应该能够识别任何材料的接缝,无论其表面纹理,眩光和阴影如何。我需要一些帮助来消除背景减去图像中的眩光,阴影和孤立点。
此外,我需要帮助摆脱外边界,并从起点到终点只获得平滑的焊缝。
我尝试使用以下代码:
a=imread('imageofworkpiece.jpg'); %http://i.imgur.com/3ngu235.jpg
b=imread('background.jpg'); %http://i.imgur.com/DrF6wC2.jpg
Ip = imsubtract(b,a);
imshow(Ip) % weldment separated %http://i.imgur.com/v7yBWs1.jpg
BW = rgb2gray(Ip);
c=edge(BW,'canny',0.05); % by trial and error
figure;imshow(c) % %http://i.imgur.com/1UQ8E3D.jpg
bw = bwareaopen(c, 100); % by trial and error
figure;imshow(bw) %http://i.imgur.com/Gnjy2aS.jpg
任何人都可以建议我采用自适应方式设置一个threhold并移除外边界以仅检测接缝吗?谢谢
答案 0 :(得分:1)
请勿使用背景
创建派生图片
dx[y][x]=pixel[y][x]-pixel[y][x-1]
对整个图像执行此操作(如果在场,则x必须在循环中减少!!!)
过滤掉低于阈值的所有派生
if (|dx[y][x]|<threshold) dx[y][x]=0; else pixel[y][x]=255;` // or what ever values you use
如何获取阈值?
计算min
和max
强度,并将阈值设置为(max-min)*scale
,其中scale
的值低于1.0
(以0.02
开头或{ {1}}例如......
也为0.1
轴
所以计算y
...并将dy[][]
和dx[][]
组合在一起。使用dy[][]
或OR
逻辑函数
过滤掉工件
您可以使用形态滤镜或平滑阈值。毕竟,你将拥有焊缝像素的掩模
如果你需要边框,那么只需遍历所有像素并记住min,max AND
coords ......
<强> [注释] 强>
如果您的图像具有良好的光照,那么您可以直接忽略推导和阈值强度,例如:
x,y
如果你想真正完全自动化,那么你必须使用自适应阈值。因此,在循环中尝试更多阈值,并根据几何尺寸,位置等记住最接近所需输出的结果......
[edit1]终于有了一些时间/心情,所以
强度图像阈值
你提供的单个图像远远不足以制作可靠的算法。这是结果
如你所见,没有进一步处理,这不是一个好方法
派生图片阈值
阈值推导x(10%)
阈值推导y(5%)
threshold = 0.5*(average_intensity+lowest_intensity)
10%di / dx和1.5%di / dy的组合
C ++ 中的代码如下所示(抱歉不要使用Matlab):
AND
int x,y,i,i0,i1,tr2,tr3;
pic1=pic0; // copy input image pic0 to pic1
pic2=pic0; // copy input image pic0 to pic2 (just to resize to desired size for derivation)
pic3=pic0; // copy input image pic0 to pic3 (just to resize to desired size for derivation)
pic1.rgb2i(); // RGB -> grayscale
// abs derivate by x
for (y=pic1.ys-1;y>0;y--)
for (x=pic1.xs-1;x>0;x--)
{
i0=pic1.p[y][x ].dd;
i1=pic1.p[y][x-1].dd;
i=i0-i1; if (i<0) i=-i;
pic2.p[y][x].dd=i;
}
// compute min,max derivation
i0=pic2.p[1][1].dd; i1=i0;
for (y=1;y<pic1.ys;y++)
for (x=1;x<pic1.xs;x++)
{
i=pic2.p[y][x].dd;
if (i0>i) i0=i;
if (i1<i) i1=i;
}
tr2=i0+((i1-i0)*100/1000);
// abs derivate by y
for (y=pic1.ys-1;y>0;y--)
for (x=pic1.xs-1;x>0;x--)
{
i0=pic1.p[y ][x].dd;
i1=pic1.p[y-1][x].dd;
i=i0-i1; if (i<0) i=-i;
pic3.p[y][x].dd=i;
}
// compute min,max derivation
i0=pic3.p[1][1].dd; i1=i0;
for (y=1;y<pic1.ys;y++)
for (x=1;x<pic1.xs;x++)
{
i=pic3.p[y][x].dd;
if (i0>i) i0=i;
if (i1<i) i1=i;
}
tr3=i0+((i1-i0)*15/1000);
// threshold the derivation images and combine them
for (y=1;y<pic1.ys;y++)
for (x=1;x<pic1.xs;x++)
{
// copy original (pic0) pixel for non thresholded areas the rest fill with green color
if ((pic2.p[y][x].dd>=tr2)&&(pic3.p[y][x].dd>=tr3)) i=0x00FF00;
else i=pic0.p[y][x].dd;
pic1.p[y][x].dd=i;
}
是输入图像
pic0
是输出图像
pic1
只是派生的临时存储
pic2,pic3
的大小为pic?.xy,pic?.ys
pic?
是像素轴(dd表示访问像素为DWORD ...)
你可以看到周围有很多东西(在你提供的第一张图片中点头可见)所以你需要进一步处理
自适应阈值:
您需要知道所需的输出图像属性(不能从单个图像输入中可靠地推断出)然后创建用变量pic.p[y][x].dd
进行上述处理的函数。尝试循环tr2,tr3
的更多选项(遍历所有值或迭代以获得更好的结果并记住最佳输出(因此您还需要一些检测输出质量的函数),例如:
tr2,tr3
在此之后 quality=0.0; param=0.0;
for (a=0.2;a<=0.8;a+=0.1)
{
pic1=process_image(pic0,a);
q=detect_quality(pic1);
if (q>quality) { quality=q; param=a; pico=pic1; }
}
应保持相对最佳的阈值图像...您应该在process_image内单独处理所有阈值,目标阈值必须按pic1
缩放,例如{{1} }
答案 1 :(得分:1)
这不能解决您找到自动阈值算法的问题。但我可以帮助隔离接缝。接缝沿着y轴(这总是这样吗?)所以我使用霍夫变换来仅隔离近垂直线。通常它会找到所有行,但我限制了theta搜索参数。我现在使用的代码恰好突出了最长的线段(我直接得到它from the matlab website)并且巧合地是焊缝。这纯属巧合。但是使用你的bwareaopened图像作为输入,霍夫线检测器能够找到接缝。当然,它需要一些玩耍才能工作,所以你会陷入原先的问题,不知何故找到最佳设置
也许这可以成为其他人的跳板 A = imread( 'weldment.jpg'); %http://i.imgur.com/3ngu235.jpg
b=imread('weld_bg.jpg'); %http://i.imgur.com/DrF6wC2.jpg
Ip = imsubtract(b,a);
imshow(Ip) % weldment separated %http://i.imgur.com/v7yBWs1.jpg
BW = rgb2gray(Ip);
c=edge(BW,'canny',0.05); % by trial and error
bw = bwareaopen(c, 100); % by trial and error
figure(1);imshow(c) ;title('canny') % %http://i.imgur.com/1UQ8E3D.jpg
figure(2);imshow(bw);title('bw area open') %http://i.imgur.com/Gnjy2aS.jpg
[H,T,R] = hough(bw,'RhoResolution',1,'Theta',-15:5:15);
figure(3)
imshow(H,[],'XData',T,'YData',R,...
'InitialMagnification','fit');
xlabel('\theta'), ylabel('\rho');
axis on, axis normal, hold on;
P = houghpeaks(H,5,'threshold',ceil(0.5*max(H(:))));
x = T(P(:,2)); y = R(P(:,1));
plot(x,y,'s','color','white');
% Find lines and plot them
lines = houghlines(BW,T,R,P,'FillGap',2,'MinLength',30);
figure(4), imshow(BW), hold on
max_len = 0;
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');
% Plot beginnings and ends of lines
plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');
% Determine the endpoints of the longest line segment
len = norm(lines(k).point1 - lines(k).point2);
if ( len > max_len)
max_len = len;
xy_long = xy;
end
end
% highlight the longest line segment
plot(xy_long(:,1),xy_long(:,2),'LineWidth',2,'Color','blue');