Search code examples
matlabimage-processingcurve-fittingbinary-image

Curve Fitting in a binary image, MATLAB


I have this Binary image bw:

enter image description here

edges of an object to carry out some measurements. But firstly I have to do curve fitting for both edges. The result should be two smooth curves representing edges.

I have the indices for each edge but I can not use them in making x-y data to be input data to a fitting function. I mean they are not x and f(x), actually, they all have the same value (1) with different positions. It is not right to say [x y]=find(BW) ; y here is not the value at x, but for sure there should be a way to use them to some kind of scale the binary image. I seem confused and I'm stuck here.

Any recommendations?


Solution

  • Why not use polyfit?

    [y x] = find( bw );  %// get x y coordinates of all curve points
    

    There are two small "tricks" you need to use here:

    1. You have two curves, thus you need to split your data points to the left and right curves

      right = x<300;
      xr = x(right);
      yr = y(right);
      xl = x(~right);
      yl = y(~right);
      
    2. Since your curves are close to vertical, it would be better to fit x=f(y) rather than the "classic" y=f(x):

      pr = polyfit( yr, xr, 3 );  %// fit 3rd deg poly
      pl = polyfit( yl, xl, 3 ); 
      

    Now you can plot them

    yy = linspace( 1, size(bw,1), 50 );
    
    figure; imshow(bw, 'border', 'tight' );
    hold all
    plot( polyval( pr, yy ), yy, '.-', 'LineWidth', 1 );
    plot( polyval( pl, yy ), yy, '.-', 'LineWidth', 1 );
    

    And you get:

    enter image description here

    If you want to create a new refined mask from the estimated curves, you can do the following:

    yy = 1:size(bw,1);  %// single value per row
    xxr=polyval(pr,yy); %// corresponding column values
    xxl=polyval(pl,yy);
    

    Set a new mask of the same size

    nbw = false(size(bw)); 
    nbw( sub2ind(size(bw),yy,round(xxr)) )=true;
    nbw( sub2ind(size(bw), yy, round(xxl) )) = true; 
    

    And the result

    figure;imshow(nbw,'border','tight');
    

    enter image description here