Skip to content

Commit 58e6c6e

Browse files
committed
imMeasures/imInscribedCircle.m: takes into account spatial calibration
1 parent 19f4107 commit 58e6c6e

File tree

2 files changed

+124
-5
lines changed

2 files changed

+124
-5
lines changed

matImage/imMeasures/imInscribedCircle.m

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
function [circle, labels] = imInscribedCircle(lbl, varargin)
2-
%IMINSCRIBEDCIRCLE Maximal circle inscribed in a particle
2+
% Maximal circle inscribed in a region.
33
%
44
% CIRC = imInscribedCircle(IMG)
55
% Computes the maximal circle inscribed in a given particle, or
66
% around each labeled particle in the input image.
77
%
8-
% CIRC = imInscribedCircle(IMG, LABELS)
8+
% CIRC = imInscribedCircle(IMG, SPACING)
9+
% CIRC = imInscribedCircle(IMG, SPACING, ORIGIN)
10+
% Takes into account the spatical calibration to compute the results in
11+
% physical units. Both SPACING and ORIGIN are 1-by-2 row vectors, that
12+
% correspond to the spacing between pixels and to the position of the
13+
% first pixel, respectively.
14+
%
15+
% CIRC = imInscribedCircle(..., LABELS)
916
% Specify the labels for which the inscribed circle needs to be computed.
1017
% The result is a N-by-3 array with as many rows as the number of labels.
1118
%
@@ -15,15 +22,15 @@
1522
% img = imFillHoles(imread('circles.png'));
1623
% imshow(img); hold on;
1724
% circ = imInscribedCircle(img);
18-
% drawCircle(circ, 'linewidth', 2)
25+
% drawCircle(circ, 'LineWidth', 2)
1926
%
2027
% % Compute and display the equivalent ellipses of several particles
2128
% img = imread('rice.png');
2229
% img2 = img - imopen(img, ones(30, 30));
2330
% lbl = bwlabel(img2 > 50, 4);
2431
% circles = imInscribedCircle(lbl);
2532
% imshow(img); hold on;
26-
% drawCircle(circles, 'linewidth', 2, 'color', 'g');
33+
% drawCircle(circles, 'LineWidth', 2, 'Color', 'g');
2734
%
2835
% See also
2936
% drawCircle, imEnclosingCircle, imInertiaEllipse, imInscribedBall
@@ -35,6 +42,27 @@
3542
% Created: 2012-07-08, using Matlab 7.9.0.529 (R2009b)
3643
% Copyright 2012 INRA - Cepia Software Platform.
3744

45+
%% Process input arguments
46+
47+
% default values
48+
spacing = [1 1];
49+
origin = [1 1];
50+
calib = false;
51+
52+
% extract spacing
53+
if ~isempty(varargin) && sum(size(varargin{1}) == [1 2]) == 2
54+
spacing = varargin{1};
55+
varargin(1) = [];
56+
calib = true;
57+
origin = [0 0];
58+
end
59+
60+
% extract origin
61+
if ~isempty(varargin) && sum(size(varargin{1}) == [1 2]) == 2
62+
origin = varargin{1};
63+
varargin(1) = [];
64+
end
65+
3866
% check if labels are specified
3967
labels = [];
4068
if ~isempty(varargin) && size(varargin{1}, 2) == 1
@@ -47,12 +75,15 @@
4775
end
4876
nLabels = length(labels);
4977

78+
79+
%% Main processing
80+
5081
% allocate memory for result
5182
circle = zeros(nLabels, 3);
5283

5384
for iLabel = 1:nLabels
5485
% compute distance map
55-
distMap = imDistanceMap(lbl==iLabel);
86+
distMap = imDistanceMap(lbl==labels(iLabel));
5687

5788
% find value and position of the maximum
5889
maxi = max(distMap(:));
@@ -61,3 +92,8 @@
6192
circle(iLabel,:) = [xc yc maxi];
6293
end
6394

95+
% apply spatial calibration
96+
if calib
97+
circle(:,1:2) = bsxfun(@plus, bsxfun(@times, circle(:,1:2) - 1, spacing), origin);
98+
circle(:,3) = circle(:,3) * spacing(1);
99+
end
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
function tests = test_imInscribedCircle
2+
% Test suite for the file imInscribedCircle.
3+
%
4+
% Test suite for the file imInscribedCircle
5+
%
6+
% Example
7+
% test_imInscribedCircle
8+
%
9+
% See also
10+
% imInscribedCircle
11+
12+
% ------
13+
% Author: David Legland
14+
15+
% Created: 2021-01-11, using Matlab 9.8.0.1323502 (R2020a)
16+
% Copyright 2021 INRAE - BIA-BIBS.
17+
18+
tests = functiontests(localfunctions);
19+
20+
function test_SimpleRect(testCase) %#ok<*DEFNU>
21+
% Test call of function without argument.
22+
23+
img = zeros(100, 100, 'uint8');
24+
img(30:60, 20:80) = 1;
25+
26+
circle = imInscribedCircle(img);
27+
28+
assertEqual(testCase, size(circle), [1 3]);
29+
assertEqual(testCase, circle(3), 16, 'AbsTol', 0.01);
30+
31+
32+
function test_MultiLabels(testCase) %#ok<*DEFNU>
33+
% Test call of function without argument.
34+
35+
img = [ ...
36+
0 0 0 0 0 0 0 0 0 0 0; ...
37+
0 1 1 1 0 4 4 4 4 4 0; ...
38+
0 1 1 1 0 4 4 4 4 4 0; ...
39+
0 1 1 1 0 4 4 4 4 4 0; ...
40+
0 0 0 0 0 0 0 0 0 0 0; ...
41+
0 6 6 6 6 6 6 6 6 6 0; ...
42+
0 6 6 6 6 6 6 6 6 6 0; ...
43+
0 6 6 6 6 6 6 6 6 6 0; ...
44+
0 6 6 6 6 6 6 6 6 6 0; ...
45+
0 6 6 6 6 6 6 6 6 6 0; ...
46+
0 6 6 6 6 6 6 6 6 6 0; ...
47+
0 6 6 6 6 6 6 6 6 6 0; ...
48+
0 6 6 6 6 6 6 6 6 6 0; ...
49+
0 6 6 6 6 6 6 6 6 6 0; ...
50+
0 6 6 6 6 6 6 6 6 6 0; ...
51+
0 0 0 0 0 0 0 0 0 0 0] ; ...
52+
53+
[circles, labels] = imInscribedCircle(img);
54+
55+
assertEqual(testCase, size(circles), [3 3]);
56+
assertEqual(testCase, length(labels), 3);
57+
58+
expRadius = [2 2 5]';
59+
assertEqual(testCase, circles(:,3), expRadius, 'AbsTol', 0.01);
60+
61+
62+
function test_LabelsTouchingImageBorder(testCase) %#ok<*DEFNU>
63+
% Test call of function without argument.
64+
65+
img = [ ...
66+
1 1 1 0 4 4 4 4 4; ...
67+
1 1 1 0 4 4 4 4 4; ...
68+
1 1 1 0 4 4 4 4 4; ...
69+
0 0 0 0 0 0 0 0 0; ...
70+
6 6 6 6 6 6 6 6 6; ...
71+
6 6 6 6 6 6 6 6 6; ...
72+
6 6 6 6 6 6 6 6 6; ...
73+
6 6 6 6 6 6 6 6 6; ...
74+
6 6 6 6 6 6 6 6 6] ; ...
75+
76+
[circles, labels] = imInscribedCircle(img);
77+
78+
assertEqual(testCase, size(circles), [3 3]);
79+
assertEqual(testCase, length(labels), 3);
80+
81+
expRadius = [3 3 5]';
82+
assertEqual(testCase, circles(:,3), expRadius, 'AbsTol', 0.01);
83+

0 commit comments

Comments
 (0)