Cannot obtain all centroids from loop and shape detection

Hello. I have some problem extracting centroid from loop.
I have code for detecting some shape in images in folder.
I have 2 problems from this code.
First, I have to extract centroids from the loop, the problem is the matrix store centroid for only 1 image, when it run the next image, the new centroid was overwritten over the centroid from previous image.
Second, for detecting shape in image, the bounding box and extent were used (I modified some code from Shape Recognition to detect ellipse). The problem is both not-perfect rectangle and not-perfect circle were detected as and ellipse but I don't want it to detect rectangle.
Could anyone help me about these please? This is the code I used. Thank you in advanced!
%Specify the folder where the files live.
myFolder = 'C:\Users\---';
filePattern = fullfile(myFolder, '*.jpg');
theFiles = dir(filePattern);
for k = 1 : length(theFiles)
baseFileName = theFiles(k).name;
fullFileName = fullfile(theFiles(k).folder,baseFileName);
originalImage = imread(fullFileName);
ROI = roipoly(originalImage,x,y); %apply ROI
imshow(ROI);
[rows, columns, numberOfColorChannels] = size(originalImage);
mask = poly2mask(x, y, rows, columns);
maskedRgbImage = originalImage .* cast(mask, 'like', originalImage); %Masking outside ROI
GRAY = rgb2gray(maskedRgbImage); %Grey scaling the image
%Binarizing image using edge detection
BW = edge(GRAY,'canny',0.4);
[B,L] = bwboundaries(BW, 'noholes');
STATS = regionprops(L, 'all'); % we need 'BoundingBox' and 'Extent'
hold on
%Detecting shape
figure,
imshow(originalImage),
hold on
T = [];
filename3 = [sprintf('%01d',k) '.jpg'];
fullname3 = fullfile(currentFolder,'Object detected images',filename3);
for i = 1 : length(STATS)
W(i) = uint8(abs(STATS(i).BoundingBox(3)-STATS(i).BoundingBox(4)) < 0.1); %If width and height of bounding box are equal(circle,square), W(i)=1, otherwise W(i)=0
W(i) = W(i) + 2 * uint8((STATS(i).Extent - 1) == 0 ); % Extent =1; If circle/ellipse, back term=0, rec/sqr back term =2
W(i) = W(i) + 4 * uint8((STATS(i).Extent - 1) <= 0.7854); %Extent = pi/4 case ellipse/circle
centroid = STATS(i).Centroid;
switch W(i)
case 5 %circle
plot(centroid(1),centroid(2),'wO');
x_centroid = centroid(1:2:end);
y_centroid = centroid(2:2:end);
T = [T; x_centroid y_centroid];
ax = gca;
exportgraphics(ax,fullname3)
case 2 %rectangle
plot(centroid(1),centroid(2),'wX');
x_centroid = centroid(1:2:end);
y_centroid = centroid(2:2:end);
T = [T; x_centroid y_centroid];
ax = gca;
exportgraphics(ax,fullname3)
case 3 %square
plot(centroid(1),centroid(2),'wS');
x_centroid = centroid(1:2:end);
y_centroid = centroid(2:2:end);
T = [T; x_centroid y_centroid];
ax = gca;
exportgraphics(ax,fullname3)
case 4 %ellipse
plot(centroid(1),centroid(2),'w+');
x_centroid = centroid(1:2:end);
y_centroid = centroid(2:2:end);
T = [T; x_centroid y_centroid]
ax =gca;
exportgraphics(ax,fullname3)
end
end
close
end

Answers (1)

You can store all centroids right after you call regionprops, if you want
STATS = regionprops(L, 'all'); % we need 'BoundingBox' and 'Extent'
allCentroidsXY = vertcat(STATS.Centroid)

7 Comments

The problem is I didn't want all centroid that program can detect. I want just some centroid that obtain from case for all images. How could I do that?
I have no idea how you want to specify the ones you want to keep or exclude. Explain it to me.
If you have any more questions, then attach your image with the paperclip icon after you read this:
Sorry for my inproper question.
My image to be calculated is 'MaskedImage' in attached file. After binarizing the image, it going to look like in 'BinaryImage' in attached file.
To specify the ones I want, which is the circle in the middle of region, I will delete the case for square and rectangle from this part of below code and store the centroid of the detected case only for every images in folder. But the problem is the program detected both rectangle and circle shape as ellipse case (case 4). So I tried the same code with simple shape as 'sampleShape' in attachment and I found that there are a lot error on it such as detected rectangle as ellipse, detecting rectangle as cirlce.
The citeria to classify the shape are that
-Circle: bounding box x = bounding box y, and extent <1
-rectangle: bounding box x =/ bounding box y, and extent =1
-square: bounding box x = bounding box y, and extent =1
-ellipse: bounding box x =/ bounding box y, and extent <= pi/4
If my question is unclear, I am really sorry. I have search a lot but I cannot find the answer. If you can help me with this, I really appreciate it. Thank you so much.
switch W(i)
case 5 %circle
plot(centroid(1),centroid(2),'wO');
x_centroid = centroid(1:2:end);
y_centroid = centroid(2:2:end);
%case 2 %rectangle
%plot(centroid(1),centroid(2),'wX');
%x_centroid = centroid(1:2:end);
%y_centroid = centroid(2:2:end);
%case 3 %square
%plot(centroid(1),centroid(2),'wS');
%x_centroid = centroid(1:2:end);
%y_centroid = centroid(2:2:end);
case 4 %ellipse
plot(centroid(1),centroid(2),'w+');
x_centroid = centroid(1:2:end);
y_centroid = centroid(2:2:end);
end
I don't know what that code is for. Basically you need to binarize the image for where it's not white. Then find bounding boxes and extents and then do the switch to examine them to see what kind of shape it is. Then put up the appropriate title and centroid marker. Something like (untested)
[r, g, b] = imsplit(rgbImage);
whiteMask = (r == 255) & (g == 255) & (b == 255);
shapeMask = imclearborder(~whiteMask);
props = regionprops(shapeMask, 'Centroid', 'BoundingBox');
allCentroidsCY = vertcat(props.Centroid)
allExtents = [props.Extent]
allBB = vertcat(props.BoundingBox
for k = 1 : numel(props)
aspectRatio = allBB(k, 3) / allBB(k, 4);
if abs(1 - aspectRatio) < 0.05
% It's a square or circle
else
% It's a rectangle or oval
end
end
I trust you know how to put in the check for extents to check for square vs circle, and for rectangle vs oval, and how to put up the right marker in the right location. If you can't figure it out, let me know.
Thank you for your suggestion. I have tried the code.
I added some conditions for seperate oval out of rectangle by extent. However, the program cannot specify the rectangle and also they detect a lot objects at the edge of objects as attachment image 'SimpleShape_result'. I also attached the binary image. Thank you so much
rgbImage = imread('10.jpg');
[r, g, b] = imsplit(rgbImage);
whiteMask = (r == 255) & (g == 255) & (b == 255);
shapeMask = imclearborder(~whiteMask);
props = regionprops(shapeMask, 'Centroid', 'BoundingBox','Extent');
allCentroidsCY = vertcat(props.Centroid)
allExtents = [props.Extent]
allBB = vertcat(props.BoundingBox)
figure,
imshow(rgbImage),
hold on
for k = 1:numel(props)
aspectRatio = allBB(k,3)/allBB(k,4);
centroid = props(k).Centroid;
if (abs(1-aspectRatio) < 0.05) && (allExtents(k) < 1) %circle/square
plot(centroid(1),centroid(2),'cO');
elseif (abs(1-aspectRatio) >= 0.05) && (allExtents(k) == 1) %rectangle
plot(centroid(1),centroid(2),'cS')
else
plot(centroid(1),centroid(2),'c+'); %rectangle/oval
end
end
Those are JPG artifacts. That is why you should never use JPG images for image analysis if you can avoid it. So change your mask to
whiteMask = (r > 240) & (g > 240) & (b > 240);
It works well! Thank you so much. But the claaify part still have problem as it cannot seperate rectangle from ellipse. Or if you have any new suggestion to classify the shape, it would be my pleasure if you can give advice. Thank you so much

Sign in to comment.

Products

Release

R2022a

Community Treasure Hunt

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

Start Hunting!