7

I have a binary image that represents a number in MATLAB:

image description

I'd like to fill all the digits. The desired result is:

enter image description here

The only thing I found was the imfill function, but that wasn't really helpfull since I've lost my inner data (the 9's inner circle for example).

Eitan T
  • 32,660
  • 14
  • 72
  • 109
user1240792
  • 334
  • 1
  • 4
  • 14

3 Answers3

6

Another possibility is to use the BWBOUNDARIES function, which:

traces the exterior boundaries of objects, as well as boundaries of holes inside these objects

That information is contained in the fourth output A, an adjacency matrix that represents the parent-child-hole dependencies.

%# read binary image
bw = imread('SUvif.png');

%# find all boundaries
[B,L,N,A] = bwboundaries(bw, 8, 'holes');

%# exclude inner holes
[r,~] = find(A(:,N+1:end));        %# find inner boundaries that enclose stuff
[rr,~] = find(A(:,r));                      %# stuff they enclose
idx = setdiff(1:numel(B), [r(:);rr(:)]);    %# exclude both
bw2 = ismember(L,idx);                      %# filled image

%# compare results
subplot(311), imshow(bw), title('original')
subplot(312), imshow( imfill(bw,'holes') ), title('imfill')
subplot(313), imshow(bw2), title('bwboundaries')

enter image description here

Amro
  • 123,847
  • 25
  • 243
  • 454
4

The problem is how to distinguish the holes from the digits. A possible ad hoc solution is filtering them by the area of the pixels inside.

function SolveSoProblem()

    I = imread('https://i.stack.imgur.com/SUvif.png');

    %Fill all the holes 
    F = imfill(I,'holes');

    %Find all the small ones,and mark their edges in the image
    bw = bwlabel(I);
    rp = regionprops(bw,'FilledArea','PixelIdxList');
    indexesOfHoles = [rp.FilledArea]<150;   
    pixelsNotToFill = vertcat(rp(indexesOfHoles).PixelIdxList); 
    F(pixelsNotToFill) = 0;
    figure;imshow(F);

    %Remove the inner area
    bw1 = bwlabel(F,4);
    rp = regionprops(bw1,'FilledArea','PixelIdxList');
    indexesOfHoles1 = [rp.FilledArea]<150;
    pixelListToRemove = vertcat(rp(indexesOfHoles1).PixelIdxList);
    F(pixelListToRemove) = 0;

    figure;imshow(F);
end

After step(1):

enter image description here

After step(2):

enter image description here

Andrey Rubshtein
  • 20,795
  • 11
  • 69
  • 104
  • 1
    Impressive solution. Thanks a lot!! The only little thing I changed was to remove objects which space is smaller than 2 pct of the image and it works great!! – user1240792 Jun 18 '12 at 10:08
0

Assuming the top-left pixel is always outside the regions to filled:

Work across the top line, copying pixels to the output image

When you come to a white pixel followed by a black pixel in the input image, start setting white pixels in the output image, until you come to black pixel followed by a white pixel.

Martin Thompson
  • 16,395
  • 1
  • 38
  • 56