6

I am trying to calculate two objects circumscribed radius and inscribed radius using the code below. I used for the inscribedRadius parameter from this script and for the circumscribed radius I used this function

I do not understand why I get for the box shape that the inscribed radius is bigger than the circumscribed radius. Any idea what is wrong? And how to fix it?

Image enter image description here

Code:

clc;
clear;

RGB = imcomplement(imread('https://i.stack.imgur.com/8WLAt.jpg'));
I = rgb2gray(RGB);
bw = imbinarize(I);
bw = imfill(bw,'holes');
imshow(bw)
hold on;  

[B,L] = bwboundaries(bw,'noholes');
stats = regionprops(L,'Centroid','MajorAxisLength');

for i = 1 : numel(stats)
    b = B{i};
    c = stats(i).Centroid;
    y = b(:,1);
    x = b(:,2);
    plot( b(:,2),b(:,1),'Color','red','linewidth',2);
    text(c(1),c(2),num2str(i),'Color','red'); 

    xMin = min(x);
    xMax = max(x);
    yMin = min(y);
    yMax = max(y);
    scalingFactor = 1000 / min([xMax-xMin, yMax-yMin]);
    x2s = (x - xMin) * scalingFactor + 1;
    y2s = (y - yMin) * scalingFactor + 1;
    mask = poly2mask(x2s, y2s, ceil(max(y2s)), ceil(max(x2s)));

    edtImage = bwdist(~mask);

    inscribedRadius = max(edtImage(:));
    [yCenter, xCenter] = find(edtImage == inscribedRadius);

    xCenter = (xCenter - 1)/ scalingFactor + xMin;
    yCenter = (yCenter - 1)/ scalingFactor + yMin;
    inscribedRadius = inscribedRadius / scalingFactor

    [circumscribedCenter,circumscribedRadius] = minboundcircle(x,y); % from https://www.mathworks.com/matlabcentral/fileexchange/34767-a-suite-of-minimal-bounding-objects?focused=3820656&tab=function
    circumscribedRadius     
end

The results are:

  • Object 1: inscribedRadius = 264, cumscribedRadius = 186.6762
  • Object 2: inscribedRadius = 130.4079, circumscribedRadius = 132.3831

The values of object 1 (box) are wrong as the inscribedRadius can not be bigger than the cumscribedRadius. They are fine for object 2 (circle)

jane
  • 567
  • 2
  • 12
  • You know what values to expect, no? So which of the two values you get is right? That narrows it down from having to debug two computations to having to debug one computation. – Cris Luengo May 25 '20 at 06:58
  • Did you step through the script with the debugger? When you do, you should look at the intermediate values to see if they match your exceptions. For example, verify if `mask` is a correct image that contains the full shape. – Cris Luengo May 25 '20 at 07:02
  • Thanks for the fast reply. I modified the script so it is possible to see the objects border and number. The results are Object 1: `inscribedRadius = single 264`, `cumscribedRadius = 186.6762`; Object 2: `inscribedRadius = single 130.4079`, `circumscribedRadius = 132.3831`. The values of object 1 (box) are wrong as the inscribedRadius can not be bigger than the cumscribedRadius. They are fine for object 2 (circle) – jane May 25 '20 at 07:13

1 Answers1

3

If you look at the mask image, you'll notice that the square shape is drawn touching the right and bottom edges of the image. There's background only along the left and top of the shape. The distance transform bwdist(~mask) subsequently computes the distance to the background for each pixel within the shape, but since there's background only to the left and top, the pixel at the bottom right of the shape has a distance of 1000, rather than 1. The distance transform is supposed to have a maximum in the middle, at a point equidistant to at least the three nearest shape edge points.

The solution is simple: poly2mask must create an image that is one pixel wider and taller:

mask = poly2mask(x2s, y2s, ceil(max(y2s)) + 1, ceil(max(x2s)) + 1);
                                          ^^^                 ^^^

With this change, the computed inscribedRadius for the square is 132, as expected.

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • Great question. I add two lines `viscircles([xCenter, yCenter],inscribedRadius,'Color','g','LineStyle','--');` and `viscircles(circumscribedCenter,circumscribedRadius,'Color','b','LineStyle','--');` at the end but I get `CENTERS and RADII must have the same number of rows.` error. It seems that both `xCenter` and `yCenter` are arrays and not a single number. Which one is the correct and how to proceed? – AsiJapan May 26 '20 at 13:40
  • @AsiJapan: it is possible that the distance transform produces multiple pixels with the same distance. `find` will return all of these as centers. You can pick any one of them, they are all equivalent. Note that an arbitrary shape can have multiple different inscribed circles of the same radius. – Cris Luengo May 26 '20 at 13:46
  • Thanks. Changed to `viscircles([xCenter(1), yCenter(1)],inscribedRadius,'Color','g','LineStyle','--');` – AsiJapan May 26 '20 at 14:39