3

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);
wrek
  • 309
  • 2
  • 13

1 Answers1

2

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).

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • Thanks again for the clarifications. I will appreciate if you can explain me how to calculate also the height. I add to me polyshape the height and width calculations but indeed it is not efficient and I fear that it is prone to errors due to the orientation degree I use. – wrek Apr 18 '20 at 08:36
  • Thanks a lot @Cris. I will use for the Podczeck shapes these lines: width = minRect(1); height = minRect(2); If you can add them to your superb solution and explanations, it will help future users. – wrek Apr 18 '20 at 17:29
  • @wrek: Thanks, I’ve added that explanation. – Cris Luengo Apr 18 '20 at 17:46
  • Based on the code below it seems that the object height is bigger than its width with this image 'https://i.stack.imgur.com/jD2Ce.png', Why? What the line `ConvexHull * [cosd(phi),-sind(phi); sind(phi),cosd(phi)]` does? – JohnSal Aug 20 '20 at 16:29
  • 1
    @JohnSal: that multiplication rotates the polygon in `ConvexHull`. I edited this answer to clarify the language, “Width” and “height” refer to the dimensions after rotating the shape so that its smallest projection is horizontal. We’re talking about the width and height of the rotated smallest bounding box. – Cris Luengo Aug 20 '20 at 16:47
  • Are the width and height dimensions of the minimal bounding box perpendicular to each other? how can I plot them? In FeretProperties regionprops they are not always perpendicular. – JohnSal Aug 21 '20 at 07:19
  • 1
    @JohnSal: The code here measures the “height” as the size perpendicular to the “width”. It computes this explicitly because this measure is not provided by `regionprops`. I recommend that you execute each of the lines of code by itself, examining the output, to understand what it does. It’s a bit of work at first, but eventually will pay off when you get more comfortable reading code. – Cris Luengo Aug 21 '20 at 13:48
  • @Cris: I read your DIPlib on-line documentation about the [FeatureShape](https://qiftp.tudelft.nl/dipref/FeatureShape.html) and based on the solution above I understand that _s_ (the shortest Feret diameter) is the `width = minRect(1)`, _l_ (the longest Feret diameter) is the `height = minRect(2)`, _sp_ (the Feret diameter perpendicular to _s_) than have to be `height = minRect(2)`. Am I right? – jane Aug 24 '20 at 17:59
  • @jane: Check [the `regionprops` docs](https://www.mathworks.com/help/images/ref/regionprops.html#buoixjn-1-properties): it measures `MaxFeretDiameter` and `MinFeretDiameter`, which correspond to `l` and `s`, respectively. `sp` is the value that it doesn't compute, and is computed by the code in this answer (`MinPerpFeretDiameter`). – Cris Luengo Aug 24 '20 at 19:56