aspiringroboticist
aspiringroboticist

Reputation: 134

Need to automatically eliminate noise in image and outer boundary of a object

i am mechanical engineering student working on a project to automatically detect the weld seam (The seam is a edge that is to be welded) present in a workshop. This gives a basic terminology involved in welding (https://i.sstatic.net/GfOik.jpg).

enter image description here enter image description here

To separate the weldment from the other objects, i have taken the background image and subtracted the foreground image having the weldment to obatin only the weldment(https://i.sstatic.net/i3eg3.jpg). After image subtraction,there are the shadow ,glare and remnant noises of subtracted background are still present.

enter image description here

As i want to automatically identify only the weld seam without the outer boundary of weldment, i have tried to detect the edges in the weldment image using canny algorithm and tried to eliminate the isolated noises using the function bwareopen.I have somehow obtained the approximate boundary of weldment and weld seam. The threshold i have used are purely on trial and error approach as dont know a way to automatically set a threshold to detect them.

The problem now i am facing is that i cant specify an definite threshold as this algorithm should be able to identify the seam of any material regardless of its surface texture,glare and shadow present there. I need some assistance to remove the glare,shadow and isolated points from the background subtracted image.

Also i need help to get rid of the outer boundary and obtain only smooth weld seam from starting point to end point.

i have tried to use the following code:

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 %https://i.sstatic.net/i3eg3.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

Can anybody please suggest me a adaptive way to set a threhold and remove the outer boundary to detect only the seam? Thank you

Upvotes: 3

Views: 340

Answers (2)

Spektre
Spektre

Reputation: 51845

from your image it looks like the weld seam will be usually very dark with sharp intensity edge so why don't you use that ?

  1. do not use background

  2. create derivation image

    dx[y][x]=pixel[y][x]-pixel[y][x-1]
    

    do this for whole image (if on place then x must decrease in loop!!!)

  3. filter out all derivations lower then thresholds

    if (|dx[y][x]|<threshold) dx[y][x]=0; else pixel[y][x]=255;` // or what ever values you use
    
  4. how to obtain threshold value ?

    compute min and max intensity and set threshold as (max-min)*scale where scale is value lower then 1.0 (start with 0.02 or 0.1 for example ...

  5. do this also for y axis

    so compute dy[][]... and combine dx[][] and dy[][] together. Either with OR or by AND logical functions

  6. filter out artifacts

    you can use morphologic filters or smooth threshold for this. After all this you will have mask of pixels of weld seam


    if you need boundig box then just loop through all pixels and remember min,max x,y coords ...

[Notes]

if your images will have good lighting then you can ignore the derivation and threshold the intensity directly with something like:

threshold = 0.5*(average_intensity+lowest_intensity)

if you want really fully automate this then you have to use adaptive thresholds. So try more thresholds in a loop and remember result closest to desired output based on geometry size,position etc ...

[edit1] finally have some time/mood for this so

  1. Intensity image threshold

    you provided just single image which is far from enough to make reliable algorithm. This is the result

    intensity threshold

    as you can see without further processing this is not good approach

  2. Derivation image threshold

    threshold derivation by x (10%)

    di/dx threshold

    threshold derivation by y (5%)

    di/dy threshold

    AND combination of both 10% di/dx and 1.5% di/dy

    di/dx AND di/dy threshold

The code in C++ looks like this (sorry do not use Matlab):

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 is input image
pic1 is output image
pic2,pic3 are just temporary storage for derivations
pic?.xy,pic?.ys is the size of pic?
pic.p[y][x].dd is pixel axes (dd means access pixel as DWORD ...)
as you can see there is a lot of stuff around (nod visible in the first image you provided) so you need to process this further

  • segmentate and separate...,
  • use hough transform ...
  • filter out small artifacts ...
  • identify object by expected geometry properties (aspect ratio,position,size)

Adaptive thresholds:

you need for this to know the desired output image properties (not possible to reliably deduce from single image input) then create function that do the above processing with variable tr2,tr3. Try in loop more options of tr2,tr3 (loop through all values or iterate to better results and remember the best output (so you also need some function that detects the quality of output) for example:

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

after this the pic1 should hold the relatively best threshold image ... You should process like this all threshold separately inside the process_image the targeted threshold must be scaled by a for example tr2=i0+((i1-i0)*a);

Upvotes: 1

andrew
andrew

Reputation: 2469

Well this doesn't solve your problem of finding an automatic thresholding algorithm. but I can help with isolation the seam. The seam is along the y axis (will this always be the case?) so I used hough transform to isolate only near vertical lines. Normally it finds all lines but I restricted the theta search parameter. The code I'm using now happens to highlight the longest line segment (I got it directly from the matlab website) and it is coincidentally the weld seam. This was purely coincidental. But using your bwareaopened image as input the hough line detector is able to find the seam. Of course it required a bit of playing around to work, so you are stuck at your original problem of finding optimal settings somehow

Maybe this can be a springboard for someone else enter image description here a=imread('weldment.jpg'); %https://i.sstatic.net/n5Wjx.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');

Upvotes: 1

Related Questions