Search code examples
matlabimage-processingedge-detection

How to classify edges with enclosed boundaries or not in Matlab?


I have the following image (replaced by the better image under EDIT):

If I use bwboundaries on the first object (the white blob), I would expect the boundary to traverse the outer part of that first white object

If I use bwboundaries on the second object (the horizontal white line), the boundary is just a horizontal line.

I was hoping there was a way that bwboundaries or some other method can somehow classify these 2 objects differently. That is, it could say the first object's boundary starts and ends at the same point, while for the second object, it starts at the left end and ends at the right end

However, if I look closely at how bwboundaries traverses these objects, I notice that for the first object, it traverses it once for 360 degrees. But for the second object, it actually starts at the left image border, goes to the right image border, AND THEN BACK towards the left image border.

How can I fix this problem for bwboundaries for the 2nd object AND correctly classify these as different objects (the 1st one's boundary should start and end at same point, the 2nd one's boundary SHOULD start and end at DIFFERENT points)?

EDIT:

This is a better image

enter image description here


Solution

  • So, I came up with the following idea: For 2d objects, the boundary has most likely unique (x, y) coordinates. For 1d objects, most (if not all) (x, y) values should be present two times. So, for each boundary, we just determine the unique values, or to be more precise the unique rows, and check if the amount has significantly decreased, e.g. using a ratio (#unique rows) / (#all rows). A simple option would be to set up one or more thresholds for the ratio, e.g. ratio > 0.95 should be a 2d object since most values are unique, and ratio < 0.55 should be a 1d object as most values were present two times.

    img = uint8(zeros(100));
    img(10:20, 10:90) = 255;
    img(80, 10:90) = 255;
    imshow(img);
    
    upperThr = 0.95;
    lowerThr = 0.55;
    
    B = bwboundaries(img);
    for k = 1:numel(B)
      b = B{k};
      origLength = size(b, 1);
      b = unique(b, 'rows');
      uniqueLength = size(b, 1);
      ratio = uniqueLength / origLength;
      printf('Object %d: ', k);
      if (ratio > upperThr)
        printf('2d object\n');
      elseif (ratio < lowerThr)
        printf('1d object\n');
      else
        printf('No idea\n');
      end
    end
    

    There's plenty of space for code improvements, I wanted to be keep it readable and easy to follow. One-liner fetishists are welcome to do what they like. ;-)