Reputation: 309
Based on this question I am trying to calculate the width and height of an object. I did so by converting the examined object to a polyshape and rotated. How can I extract the width and height of the rotated polyshape object? Is there a way to do it using regionprop and will it be more efficient?
Code:
clc;
clear;
close all;
Image = rgb2gray(imread('pillsetc.png'));
BW = imbinarize(Image);
BW = imfill(BW,'holes');
BW = bwareaopen(BW, 100);
[B,L] = bwboundaries(BW,'noholes');
imshow(Image);
hold on;
k=3;
stat = regionprops(BW,'Centroid','Orientation','MajorAxisLength');
b = B{k};
yBoundary = b(:,2);
xBoundary = b(:,1);
centroidObject = stat(k).Centroid;
xCentre = centroidObject(:,2);
yCentre = centroidObject(:,1);
plot(yCentre, xCentre, 'r*')
orientationDegree = stat(k).Orientation
hlen = stat(k).MajorAxisLength/2;
cosOrient = cosd(stat(k).Orientation);
sinOrient = sind(stat(k).Orientation);
xcoords = xCentre + hlen * [cosOrient -cosOrient];
ycoords = yCentre + hlen * [-sinOrient sinOrient];
plot(yBoundary, xBoundary, 'r', 'linewidth', 3);
pgon = polyshape(yBoundary, xBoundary);
polyRot = rotate(pgon,(90+orientationDegree),centroidObject);
plot(polyRot);
[xlim,ylim] = boundingbox(polyRot);
Height = xlim(2) - xlim(1);
Width = ylim(2) - ylim(1);
Upvotes: 3
Views: 343
Reputation: 60514
I would use the angle returned by the minimum Feret diameter calculation to rotate the polygon. Usually, the box at this rotation is the box with minimal area (exceptions seem to be very rare). The 'Orientation' feature is computed based on the best fit ellipse, and would not necessarily yield a small box.
Instead of rotating the full object polygon, you can also rotate only the convex hull, which typically contains fewer points and thus would be more efficient. The Feret computation already uses the convex hull, so there is no additional cost to requesting it from regionprops
.
This is code that does what I describe:
Image = rgb2gray(imread('pillsetc.png'));
BW = imbinarize(Image);
BW = imfill(BW,'holes');
BW = bwareaopen(BW, 100);
stat = regionprops(BW,'ConvexHull','MinFeretProperties');
% Compute Feret diameter perpendicular to the minimum diameter
for ii=1:numel(stat)
phi = stat(ii).MinFeretAngle; % in degrees
p = stat(ii).ConvexHull * [cosd(phi),-sind(phi); sind(phi),cosd(phi)];
minRect = max(p) - min(p); % this is the size (width and height) of the minimal bounding box
stat(ii).MinPerpFeretDiameter = minRect(2); % add height to the measurement structure
end
Note that the first value of minRect
in the code above is the width of the object (smallest side of minimum bounding box), and equivalent to stat(ii).MinFeretDiameter
. The two values are not identical because they are computed differently, but they are pretty close. The second value of minRect
, which is saved as “MinPerpFeretDiameter”, is the height (or rather the longest side of the minimum bounding box).
Upvotes: 2