In my progress work, I have to detect a parasite. I have found the parasite using HSV and later made it into a grey image. Now I have done edge detection too. I need some code which tells MATLAB to find the largest contour (parasite) and make the rest of the area as black pixels.
-
That's quite vague, can you elaborate/provide sample image/code please? Otherwise you might be interested in [regionprops](http://www.mathworks.com/help/images/ref/regionprops.html) – Benoit_11 Feb 19 '15 at 18:32
-
I have added the image now @Benoit_11. I haven't written any code. I want to have only the the large area covered line ( like a cashew shape ) there and to make the rest into black pixels. I by reading the other related question at stack overflow learnt that I should use contour and if I can write any code in order to choose the large contour I can make it work. But I have no clue how to do that. – Jae Feb 19 '15 at 18:38
3 Answers
You can select the "largest" contour by filling in the holes that each contour surrounds, figure out which shape gives you the largest area, then use the locations of the largest area and copy that over to a final image. As what Benoit_11 suggested, use regionprops
- specifically the Area
and PixelList
flags. Something like this:
im = imclearborder(im2bw(imread('https://i.stack.imgur.com/a5Yi7.jpg')));
im_fill = imfill(im, 'holes');
s = regionprops(im_fill, 'Area', 'PixelList');
[~,ind] = max([s.Area]);
pix = sub2ind(size(im), s(ind).PixelList(:,2), s(ind).PixelList(:,1));
out = zeros(size(im));
out(pix) = im(pix);
imshow(out);
The first line of code reads in your image from StackOverflow directly. The image is also a RGB image for some reason, and so I convert this into binary through im2bw
. There is also a white border that surrounds the image. You most likely had this image open in a figure
and saved the image from the figure. I got rid of this by using imclearborder
to remove the white border.
Next, we need to fill in the areas that the contour surround, so use imfill
with the holes
flag. Next, use regionprops
to analyze the different filled objects in the image - specifically the Area
and which pixels belong to each object in the filled image. Once we obtain these attributes, find the filled contour that gives you the biggest area, then access the correct regionprops
element, extract out the pixel locations that belong to the object, then use these and copy over the pixels to an output image and display the results.
We get:
Alternatively, you can use the Perimeter
flag (as what Benoit_11) suggested, and simply find the maximum perimeter which will correspond to the largest contour. This should still give you what you want. As such, simply replace the Area
flag with Perimeter
in the third and fourth lines of code and you should still get the same results.

- 102,964
- 22
- 184
- 193
-
Haha I was writing the exact same answer but with the `Perimeter` flag :) Well done and +1 of course. – Benoit_11 Feb 19 '15 at 18:59
-
@Benoit_11 - Oh yeah! Perimeter would work here too. D'oh lol. You should still put your answer in :) I'll +1 it too. – rayryeng Feb 19 '15 at 19:02
This could be one approach -
%// Read in image as binary
im = im2bw(imread('https://i.stack.imgur.com/a5Yi7.jpg'));
im = im(40:320,90:375); %// clear out the whitish border you have
figure, imshow(im), title('Original image')
%// Fill all contours to get us filled blobs and then select the biggest one
outer_blob = imfill(im,'holes');
figure, imshow(outer_blob), title('Filled Blobs')
%// Select the biggest blob that will correspond to the biggest contour
outer_blob = biggest_blob(outer_blob);
%// Get the biggest contour from the biggest filled blob
out = outer_blob & im;
figure, imshow(out), title('Final output: Biggest Contour')
The function biggest_blob
that is based on bsxfun
is an alternative to what other answers posted here perform with regionprops
. From my experience, I have found out this bsxfun
based technique to be faster than regionprops
. Here are few benchmarks comparing these two techniques for runtime performances on one of my previous answers.
Associated function -
function out = biggest_blob(BW)
%// Find and labels blobs in the binary image BW
[L, num] = bwlabel(BW, 8);
%// Count of pixels in each blob, basically should give area of each blob
counts = sum(bsxfun(@eq,L(:),1:num));
%// Get the label(ind) cooresponding to blob with the maximum area
%// which would be the biggest blob
[~,ind] = max(counts);
%// Get only the logical mask of the biggest blob by comparing all labels
%// to the label(ind) of the biggest blob
out = (L==ind);
return;
Debug images -
-
Ah. `bwlabel` with `bsxfun`. Another valid approach. It doesn't rely on `regionprops`. +1. – rayryeng Feb 19 '15 at 19:14
-
-
I do like the fact that you used that to count how many pixels belonged to each object. Curious: How do you think `accumarray` would compare to `bsxfun` in this case? Comparable? Faster? Slower? – rayryeng Feb 19 '15 at 19:18
-
-
1
-
@rayryeng Actually accumarray could be interesting! In fact since you would use this function so many times on IP problems, give it a try?? How about `histc`? – Divakar Feb 19 '15 at 19:24
-
@Divakar - I know for sure `histc` would be slower. I'm gonna try some stuff right now and get back to you :) I'll do some `timeit` with your code. I'd simply be replacing the line that counts up how many pixels belongs to each object. – rayryeng Feb 19 '15 at 19:26
-
@Divakar - Wow... I'm very surprised. I did some simple `tic` `toc` testing and over the 10 times I ran it, `bsxfun` ran for: 0.001058126 seconds, `accumarray`: 0.002268824 seconds and `histc`: 0.000631483 seconds. I only benchmarked the counting labels part. I'm really surprised how `histc` did better. – rayryeng Feb 19 '15 at 19:32
-
1@rayryeng Told you!! At first glance looked perfect for `histc`, because that's what histc is made for (to count) which is what we are doing here! – Divakar Feb 19 '15 at 19:32
-
@Divakar - lol of course. This was a really interesting test. Thanks! – rayryeng Feb 19 '15 at 19:42
Since my answer was pretty much all written out I'll give it to you anyway, but the idea is similar to @rayryeng's answer.
Basically I use the Perimeter
and PixelIdxList
flags during the call to regionprops
and therefore get the linear indices of the pixels forming the largest contour, once the image border has been removed using imclearborder
.
Here is the code:
clc
clear
BW = imclearborder(im2bw(imread('https://i.stack.imgur.com/a5Yi7.jpg')));
S= regionprops(BW, 'Perimeter','PixelIdxList');
[~,idx] = max([S.Perimeter]);
Indices = S(idx).PixelIdxList;
NewIm = false(size(BW));
NewIm(Indices) = 1;
imshow(NewIm)
And the output:
As you see there are many ways to achieve the same result haha.

- 13,905
- 2
- 24
- 35
-
1Ah `PixelIdxList`. Smart. It removes the unnecessary `sub2ind` call I made. +1. – rayryeng Feb 19 '15 at 19:12
-
Why does it give this error everytime i run it?: ??? [~,idx] = max([S.Perimeter]); | Error: Expression or statement is incorrect--possibly unbalanced (, {, or [. – Apurv Jul 03 '15 at 05:59
-