MATLAB: Delete an unwanted blob in binary image

image analysisimage processingImage Processing Toolboximage segmentation

Hello, I'm trying to delete the unwanted blobs in an image using their shape as criteria. I have already deleted the blobs that are bigger than the objects that I want to look for using a pixel count. In the example image that I attach you can see 5 blobs, I'd like to keep the 2 that are most similar to a circle and delete the rest. I have tried to do the following but didn't succeed. It is supposed to calculate the ratio of Perimeter/Area and delete the blobs that are above a defined value. Maybe it's a matter of element classes and mixing binary images with RGB, I'm quite a newbie with Matlab.
Daurat is a binary image that I use as mask
[labeledImage numberOfBlobs] = bwlabel(Daurat, 8);
blobMeasurements = regionprops(labeledImage, Daurat, 'Area', 'Centroid', 'Perimeter', 'PixelList');
areas(:,1) = [blobMeasurements.Area]
if max(areas)>1500
grans = uint8(bwareaopen(Daurat, 1500));
Daurat = Daurat-grans;
[labeledImage numberOfBlobs] = bwlabel(Daurat, 8);
blobMeasurements = regionprops(labeledImage, Daurat, 'Area', 'Centroid', 'Perimeter', 'PixelList');
clearvars areas;
areas(:,1) = [blobMeasurements.Area];
subplot(2,2,4);
imshow (Daurat,[])
end
per(:,1) = [blobMeasurements.Perimeter];
r(:,1) = zeros(numberOfBlobs,1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Doesn't work
for i=1:numberOfBlobs;
r(i)=per(i)/areas(i)
P=[blobMeasurements(i).PixelList];
if r(i)>0.3
Daurat(P)=0;
end
end
clearvars labeledImage numberOfBlobs blobMeasurements;
[labeledImage numberOfBlobs] = bwlabel(Daurat, 8);
blobMeasurements = regionprops(labeledImage, Daurat, 'Area', 'Centroid', 'Perimeter', 'PixelList');
clearvars areas;
areas(:,1) = [blobMeasurements.Area];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
I don't know if I explained myself correctly, don't hesitate to ask for more info

Best Answer

A glaring error with your code is this:
P=[blobMeasurements(i).PixelList];
Daurat(P)=0;
PixelList is a 2d-array of [columns rows], you then use as a 1d-array to set pixels black. Instead of PixelList, you need to use PixelIdxList which is a 1d-array of pixel indices. So change your regionprops to:
blobMeasurements = regionprops(labeledImage, Daurat, 'Area', 'Centroid', 'Perimeter', 'PixelIdxList');
A more important issue is that the test you're doing does not guarantee you a shape close to circle. The r you're calculating is
- for a circle of radius R: r = 2*pi*R/(pi*R^2) = 2/R
- for a square of side 2R: r = 4*2*R/(2R * 2R) = 2/R
- for a thin rectangle of sides a=202R/200 and b = 100*a: r = 2/R
Thus, you can find any shape with a r >0.3.
You would be better off using the Eccentricity property returned by regionprops. An Eccentricity of 0 is a perfect cirle, 1 is a line. Thus I would have:
blobMeasurements = regionprops(labeledImage, Daurat, 'Area', 'Centroid', 'Perimeter', 'PixelIdxList', 'Eccentricity');
for i=1:numberOfBlobs %no need for semicolon. Actually it looks odd.
if blobMeasurements(i).Eccentricity > 0.85 %arbitrary value for you to choose
Daurat(blobMeasurements(i).PixelIdxList) = 0;
end
end
One final thing:
per(:,1) = [blobMeasurements.Perimeter];
is equivalent to:
per = [blobMeasurements.Perimeter]';
which looks less odd to me. In any case you don't need it as a column vector so I would just have:
per = [blobMeasurements.Perimeter]; %same for Area