首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >需要自动消除图像中的噪声和对象的外边界

需要自动消除图像中的噪声和对象的外边界
EN

Stack Overflow用户
提问于 2015-03-06 16:14:00
回答 2查看 275关注 0票数 3

我是一个机械工程专业的学生,正在做一个项目,自动检测车间中存在的焊接缝(接缝是要焊接的边)。这提供了焊接相关的基本术语(http://i.imgur.com/Hfwjq0w.jpg)。

为了将焊接件与其他对象分开,我拍摄了背景图像,并减去具有焊接件的前景图像,以仅获得焊接件(http://i.imgur.com/v7yBWs1.jpg)。图像相减后,背景仍然存在阴影、眩光和残馀噪声。

由于我只想自动识别没有焊接件外部边界的焊缝,所以尝试用canny算法检测焊接件图像中的边缘,并尝试使用bwareopen.I函数消除孤立的噪声,以某种方式获得了焊接件和焊缝的近似边界。我使用的阈值纯粹是试错法,因为我不知道如何自动设置阈值来检测它们。

我现在面临的问题是,我不能指定一个明确的阈值,因为这个算法应该能够识别任何材料的接缝,而不管它的表面纹理,眩光和阴影存在。我需要一些帮助,以消除眩光,阴影和孤立的点从背景减去图像。

另外,我需要帮助摆脱外部边界,只获得平滑的焊缝从起点到终点。

我尝试使用以下代码:

代码语言:javascript
运行
复制
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

有没有人可以建议我一种合适的方法来设置一个三叉线,并去除外部边界,只检测接缝?谢谢

EN

回答 2

Stack Overflow用户

发布于 2015-03-06 17:10:36

从你的图像看,焊缝通常会很暗,边缘很清晰,所以你为什么不使用它呢?

  1. do不使用background
  2. create派生映像

dxy=像素像素

对整个图像执行此操作(如果启用,则x必须在低于阈值的所有派生的loop!!!)

  • filter中减小

if (|dxy|

  • how获得阈值?

计算minmax强度并将阈值设置为(max-min)*scale,其中scale的值小于1.0 (例如,以0.020.1开头,这也适用于轴

所以计算dy[][]...并将dx[][]dy[][]结合在一起。使用OR或by AND logical functions

  • filter out工件

您可以使用形态过滤器或平滑阈值。在所有这一切之后,你将有像素面的焊缝

如果你需要边界框,那么只需循环所有像素,并记住最小,最大x,y坐标…

笔记

如果你的图像会有很好的光照,那么你可以忽略导数,直接用下面的东西来设置强度阈值:

代码语言:javascript
运行
复制
threshold = 0.5*(average_intensity+lowest_intensity)

如果你真的想要完全自动化,那么你必须使用自适应阈值。因此,在循环中尝试更多的阈值,并根据几何尺寸、位置等记住最接近所需输出的结果。

edit1终于有时间/心情来做这个了,所以

  1. Intensity图像阈值

你只提供了一张图片,这远远不足以做出可靠的算法。这是的结果

如您所见,如果不进行进一步处理,这不是一种好方法

  1. Derivation图像阈值

由x (10%)导出的阈值

阈值派生y (5%)

10%di/dx和1.5%di/dy的AND组合

C++中的代码如下所示(抱歉,请不要使用Matlab):

代码语言:javascript
运行
复制
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?.yspic?的大小

pic.p[y][x].dd是像素轴(dd表示访问像素为DWORD...)

正如您所看到的,周围有很多东西(在您提供的第一张图像中可以看到点头),因此您需要进一步处理它

  • 分割和分离...,
  • 使用霍夫变换...
  • 过滤出较小的伪像...
  • 通过预期的几何属性(纵横比、位置、大小)识别对象

自适应阈值:

为此,您需要知道所需的输出图像属性(不可能从单个图像输入中可靠地推断出),然后创建使用变量tr2,tr3执行上述处理的函数。在循环中尝试tr2,tr3的更多选项(循环所有值或迭代以获得更好的结果,并记住最佳输出(因此您还需要一些检测输出质量的函数),例如:

代码语言:javascript
运行
复制
    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; }
     }

在此之后,pic1应该保持相对最佳的阈值图像...您应该像这样在process_image中单独处理所有阈值目标阈值必须由a进行缩放,例如tr2=i0+((i1-i0)*a);

票数 1
EN

Stack Overflow用户

发布于 2015-03-07 09:18:47

这并不能解决寻找自动阈值算法的问题。但我可以帮你隔离接缝。接缝是沿y轴的(这种情况总是这样吗?)因此,我使用hough变换来分离靠近垂直线的部分。通常它会查找所有行,但我限制了theta搜索参数。我现在使用的代码恰好高亮显示了最长的线段(我直接用from the matlab website得到的),碰巧的是它是焊缝。这纯属巧合。但是使用你的bwareaopened图像作为输入,hough线检测器能够找到接缝。当然,它需要一些玩耍才能奏效,所以你会陷入寻找最优设置的原始问题上

也许这可以成为别人的跳板

代码语言:javascript
运行
复制
 a=imread('weldment.jpg'); %[http://i.imgur.com/3ngu235.jpg](https://i.imgur.com/3ngu235.jpg)
代码语言:javascript
运行
复制
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');
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28894607

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档