# find figures (squares, rectangles, circles) with matlab

33 views (last 30 days)
Cristian De la Vega on 3 Apr 2022
Edited: DGM on 3 Apr 2022
Propose an algorithm that allows to identify the shape of the object between whether it is square, rectangular, round or oval
Walter Roberson on 3 Apr 2022
Hint: eccentricities

DGM on 3 Apr 2022
@Image Analyst's answer is leagues better than this, but I was toying with it last night. I figured I'd throw it out there. I used a bit different approach to identify general ellipses, although the peak-finding results will also identify them, since they'd appear as 2-gons.
Note that the assumption is made that any non-ellipse is a polygon, which isn't necessarily true. Also note that I'm only counting convex vertices, so in the case of a non-convex polygon, the vertex count is less than the total number of vertices. Also, the polygons are not tested for regularity.
% say we have a grayscale image
inpict = ~imbinarize(rgb2gray(inpict));
S = regionprops(inpict,'centroid','boundingbox','extent','solidity', ...
'majoraxislength','minoraxislength','area');
numobj = numel(S);
% find aspect ratio
bbsize = vertcat(S.BoundingBox);
bbsize = bbsize(:,3:4);
AR = min(bbsize,[],2) ./ max(bbsize,[],2);
% find ellipse-ness
ell = vertcat(S.Area)./(pi*vertcat(S.MinorAxisLength).*vertcat(S.MajorAxisLength))*4;
% find number of apparent convex vertices
L = bwlabel(bwperim(inpict));
numpeaks = zeros(1,numobj);
for k = 1:numobj
% calculate the object radius, sorted by angle
[y x] = find(L==k);
dv = [x y] - S(k).Centroid;
r = sqrt(sum((dv).^2,2));
th = atan2d(dv(:,2),dv(:,1));
[th idx] = sort(th);
r = r(idx);
% truncate values near the minimum radius
% to avoid counting false peaks when variation is small (circles)
mn = min(r);
r = max(r-mn-10,0);
[pk idx] = findpeaks(r,'minpeakprominence',10);
numpeaks(k) = numel(pk);
% in case a peak happens to line up with the starting angle
% shift by half the apparent vertex angle and check again
if numpeaks(k) == 0
shiftamt = numel(r)/2;
else
shiftamt = idx(1)/2;
end
r = circshift(r,round(shiftamt));
[pk idx] = findpeaks(r,'minpeakprominence',10);
% pick the larger of the two counts
numpeaks(k) = max(numel(pk),numpeaks(k));
end
% classify the objects
% if we can assume there are only two categories of shapes present
% then all non-ellipses are polygons
isconvex = vertcat(S.Solidity)>0.9; % might help distinguish stars from convex shapes
isrectangle = vertcat(S.Extent)>0.9; % this includes squares
issquare = isrectangle & AR>0.9; % only regular rectangles (there are none)
isellipse = ell>0.99; % includes circles
iscircle = isellipse & AR>0.9; % only regular ellipses
% display object numbers and print conclusions
imshow(inpict)
for k = 1:numobj
c = S(k).Centroid;
t = text(c(1),c(2),sprintf('%d',k));
t.Color = 'k';
t.HorizontalAlignment = 'center';
if isrectangle(k)
if issquare(k)
fprintf('Object %d is a square\n',k)
else
fprintf('Object %d is a rectangle\n',k)
end
elseif isellipse(k)
if iscircle(k)
fprintf('Object %d is a circle\n',k)
else
fprintf('Object %d is an ellipse\n',k)
end
elseif isconvex(k)
fprintf('Object %d is a %d-gon\n',k,numpeaks(k))
else
% this assumes that the only remaining cases are still polygons
% this isn't necessarily true, but i'm sure one could further refine
% tests to count non-convex vertices, test for regularity, etc
fprintf('Object %d appears to be a non-convex polygon with %d convex vertices\n',k,numpeaks(k))
end
end
Object 1 is an ellipse
Object 2 is a rectangle Object 3 is a rectangle Object 4 is a rectangle
Object 5 is a circle
Object 6 is an ellipse
Object 7 is a 3-gon
Object 8 is a rectangle
Object 9 is a circle Object 10 appears to be a non-convex polygon with 5 convex vertices
DGM on 3 Apr 2022
Edited: DGM on 3 Apr 2022
That's a good point. The regionprops() docs mentions that, but it's easy to miss.
With the specific method we're using wherein the object radius is analyzed to find the number of vertices, the shape needs to be reasonably large. As the shape gets smaller, the asperities caused by quantization end up becoming significant features and excluding them becomes harder.
The way I wrote the above example, this line:
r = max(r-mn-10,0);
relies on the variation in object radius being at least 2*10 pixels. This will tend to fail before the code starts picking up spurious vertices. You'll know it fails if it tells you it found a 0-gon. For cases smaller than this clamping routine allows, you'd likely have to adjust the arguments to findpeaks() as well.
If irregular polygons are allowed (or shapes with holes), everything may fail spectacularly.

### More Answers (1)

Image Analyst on 3 Apr 2022
regionprops() now has a 'Circularities' option.
See my attached shape recognition demos. One uses circularity but I think the more robust one is one that plots the distance of the perimeter from the centroid and looks for peaks, which counts the number of vertices.