user1240792
user1240792

Reputation: 334

Fill area between two connected components in MATLAB

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).

Upvotes: 7

Views: 12901

Answers (3)

Andrey Rubshtein
Andrey Rubshtein

Reputation: 20915

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.sstatic.net/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

Upvotes: 4

Amro
Amro

Reputation: 124563

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

Upvotes: 6

Martin Thompson
Martin Thompson

Reputation: 16792

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.

Upvotes: 0

Related Questions