fill a boundary region with white colour

i have identified boundaries from a binary image using
boundaries = bwboundaries(bw);
The output of the above line of code is shown below
[108,69;108,69]
[691,69;691,69]
23x2 double
i wanted to select boundaries{2} and boundaries{3} and fill that region with white colour, how can i do it?

7 Comments

@Elysi, I'd really like to know your logic for accepting the answer you've accepted, so I know whether or not to waste my time on any of your future questions.
We've narrowed down in Image Analyst's answer that what you actually wanted to do is remove the two largest blobs of your image. You were provided with two solutions that do exactly that but you go and accept the one solution that doesn't do that, so it really feels that we wasted our time helping you.
Sorry Guillaume
i tried your code
tofill = bwareafilt(bw, 2, 'largest');
bw(tofill) = 0;
but in some images some of the regions i wanted also got filled
i changed his condition
if k <length(B)/2
and i gave the range for area, instead of that condition, and it worked
Thats why i accepted his answer
Sorry sir to make you feel as "It really feels that we wasted our time helping you"
Please never think that way
Your suggestions and answers helps me a lot to think and get solutions for other answers too,
So sir never think it as a waste of time. Please spend your precious time in helping me to give solutions.
I really need them and keep waiting for answers and suggestions
Thank you Guillaume Image Analyst and Thiago Henrique Gomes Lobato for your answers and suggestions
That's fine then. But do comment on the answers you're given, so we know that our answers are useful or at least taken into account.
Sure sir, i will do it again. Once again sorry sir and please keep posting your answers and suggestions. Thank you sir
Elysi, now I / we think perhaps you want to extract only the second and third largest blob, considering their size after filling, which is a completely different thing than what were first answering about blob #2 and blob #3 using numbers as gotten from something like bwboundaries() and bwlabel(). With those, they give labels according to whatever order it finds a blob as scanning proceeds in column-major order, which is down the rows in one column (until it sees a white pixel), then move over to the next column and go down its rows, and so on until all columns have finally been scanned.
if you want to fill and keep the second and third largest blobs, you could simply have done:
bw = imfill(bw, 'holes'); % Fill FIRST!
props = regionprops(bw, 'Area'); % Measure areas of all blobs.
sortedAreas = sort([props.Area], 'descend'); % Get all areas into one vector sorted by decreasing area.
% Use bwareafilt to keep only blobs in the range from the second largest to third largest.
bw = bwareafilt(bw, [sortedAreas(3), sortedAreas(2)]);
No need for any boundary or labelling nonsense.
But reading and rereasing all your questions and comments I can't tell if you want to keep only the 2nd and 3rd largest blobs, or remove them from the rest of the image. The code above keeps them and discards all others. If instead you want to remove them and keep all other blobs as in the original mask (unfilled), then do this:
filledBlobs = imfill(bw, 'holes'); % Fill FIRST!
props = regionprops(filledBlobs, 'Area'); % Measure areas of all blobs.
sortedAreas = sort([props.Area], 'descend'); % Get all areas into one vector sorted by decreasing area.
% Use bwareafilt to keep only blobs in the range from the second largest to third largest.
blobs2and3 = bwareafilt(filledBlobs, [sortedAreas(3), sortedAreas(2)]);
% Now erase the 2nd and 3rd blobs from the original bw (unfilled) image.
bw(blobs2and3) = false;
Again, none of us would use boundaries. And it would be nice to finally know if you want to keep or eliminate the 2nd and 3rd largest blobs.
I also wonder why you're doing this. Is it something to do with artifact removal, like after thresholding you get a huge portion of the background? If it's something like that, then a better option would probably be to to a background correction (flattening) before doing a global threshold.
Thank you Image Analyst sir
Through your previous suggestions itself i did changed the use of bwboundaries
Your below code worked for me
filledBlobs = imfill(bw, 'holes'); % Fill FIRST!
props = regionprops(filledBlobs, 'Area'); % Measure areas of all blobs.
sortedAreas = sort([props.Area], 'descend'); % Get all areas into one vector sorted by decreasing area.
% Use bwareafilt to keep only blobs in the range from the second largest to third largest.
blobs2and3 = bwareafilt(filledBlobs, [sortedAreas(3), sortedAreas(2)]);
% Now erase the 2nd and 3rd blobs from the original bw (unfilled) image.
bw(blobs2and3) = false;
Sir actually i had few set of images, in those set, not all but most of the images had 2nd and 3rd largest blob i wanted to eliminate. So first i thought of keeping only those working images. Then when i tried keeping the range condition for area, few more images worked.
Thank you Image Analyst sir for your detailed explanation. Your suggestions and answers have always been like teachings to me, from the time i have joined Mathworks. Thank you sir
How do you decide which to keep in the various images? What are you looking at? What criteria is it that you check to determine which blobs to keep and which to discard?

Sign in to comment.

 Accepted Answer

You can transform the contourns in a binary image, fill it and than translate it back to your original image. Here is an example adapted from the matlab bwboundaries documentation.
I = imread('rice.png');
BW = imbinarize(I);
[B,L] = bwboundaries(BW,'noholes');
figure
imshow(label2rgb(L, @jet, [.5 .5 .5]))
hold on
for k = 1:length(B)
boundary = B{k};
if k <length(B)/2 % Half with fill and half without so one can verify the difference between them
% Binary image with same size
Ibinary = I==0;
% Get contourn image and plot it in the binary image
ind = sub2ind(size(Ibinary),boundary(:,2),boundary(:,1));
Ibinary(ind) = 1;
% Close the binary image
Ibinary = imfill(Ibinary,'holes');
% Get combination of index and plot in the figure
Index = find(Ibinary==1);
[row,col] = ind2sub(size(Ibinary),Index);
plot(row,col , 'w', 'LineWidth', 2)
else % Matlab example with only the boundaries
plot(boundary(:,2), boundary(:,1), 'w', 'LineWidth', 2)
end
end
untitled.jpg

6 Comments

Guillaume
Guillaume on 24 Nov 2019
Edited: Guillaume on 24 Nov 2019
This is a bit backward. bwboundaries has two steps. The first step calls bwlabel to identify each object in the image. At this point you have all the pixels inside the boundary.
Then bwboundaries traces the outside (and inside if tracing 'holes') of each label to get you the boundary pixel. What you're doing here is reverse the tracing to get back at the pixels returned by bwlabel. Lots of work for nothing!
i'm getting error as
Error using sub2ind
Out of range subscript.
Error in ex_rice
ind = sub2ind(size(Ibinary),boundary(:,2),boundary(:,1));
You get that error running the exact same code I posted or your own? When I literally just copy and paste it by me it works fine. This error is when a point combination in the boundary array is bigger than the maximum linear index of the image, so maybe you're using a different image to generate the mask binary from the one to calculate the boundaries?
And Guillaume, it is indeed a kind of reverse work, but it could be that the other contours are needed for something else, and if this is indeed the case in your approach one would need use bwlabel, get the needed regions, then either use bwboundaries again or implement the additional routines in the other select regions, also lots of work. If the other contours aren't needed than it would be more efficient
i tried with rice.png and it works without errors
but when i try with mine i get the sub2ind error
is it because the output of my line
boundaries = bwboundaries(bw);
is
9x2 double
7x2 double
[108,69;108,69]
[691,69;691,69]
23x2 double
105x2 double
It actually shoudn't matter how the different outpus are done, could you maybe post your image?
"And Guillaume, it is indeed a kind of reverse work, but it could be that the other contours are needed for something else, and if this is indeed the case in your approach one would need use bwlabel, get the needed regions, then either use bwboundaries again or implement the additional routines in the other select regions, also lots of work. If the other contours aren't needed than it would be more efficient"
If the boundaries are needed for something else, then grab the 2nd output of bwboundaries then. It's the same labeled image returned by bwlabel. Tracing the boundaries and the reverse operation of flood filling a boundary are both complex operations, so doing one just to reverse it is a bit of a waste:
[boundaries, labelimage] = bwboundaries(bw); %labelimage is the output of bwlabel(bw) that bwboundaries call.

Sign in to comment.

More Answers (2)

Guillaume
Guillaume on 24 Nov 2019
Edited: Guillaume on 24 Nov 2019
boundaries{2} is only two pixels, there's nothing to fill!
Anyway, if all you want is to fill the region, then bwboundaries is a waste of time. You only need the first step of the bwboundaries algorithm, which is the region labels obtained with bwlabel.
labels = bwlabel(bw);
white = uint8(255); %or 1 if your image is double
bw(ismember(labels, [2 3]) = white; %fill pixels whose labels are 2 or 3 with white.
edit: so it turns out you want to fill the two largest objects of your image. Why didn't you ask help on that to start with?
The easiest way to fill the two largest blobs of image bw:
tofill = bwareafilt(bw, 2, 'largest');
bw(tofill) = 0;
done!
Simply do this:
bw = imfill(bw, 'holes');
since boundaries came from BW, and the first two boundaries are not really closed boundaries, the code above will fill the third boundary in bw.

4 Comments

First of all, imfill() does NOT remove any areas. Secondly you should not do that for loop to get all the areas. Simply do
allAreas = [props.Area];
Explain why you're extracting the boundaries in the first place. From what I've seen so far, they are not needed at all. What are you really after anyway?
To extract and fill the 2nd and 3rd blobs, do this:
indexes = [sortIndexes(2), sortIndexes(3)];
blobs2and3 = ismember(labeledImage, indexes); % This is a binary image of only blobs 2 and 3.
% Now get binary image without them. Erase them from the original binary image.
bw = imfill(blobs2and3, 'holes');
Now you can relabel, call regionprops or whatever you want to do.
As I explained already, tracing the boundaries of a region just to fill it is a complete waste of time. You've already got all the pixels of each region from bwlabel. You also got them again from regionprops, so using the slow bwboundaries to get something less useful is pointless.
In any case, if you want to fill the two largest blobs, bwareafilt is probably the best function. See edit to my answer.
Right. No need to call bwboundaries(), and better to extract what is wanted in advance with bwareafilt() than to get properties of them with regionprops(), and then figure out from the areas which ones to keep.

Sign in to comment.

Categories

Find more on Particle & Nuclear Physics in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!