Mercurial > hg > octave-image
annotate inst/regionprops.m @ 561:c45838839d86
maint: update license to GPLv3 and mention non GPL files
author | carandraug |
---|---|
date | Mon, 16 Apr 2012 12:49:47 +0000 |
parents | 39a521b5484e |
children | 67d43bf75000 |
rev | line source |
---|---|
561
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
1 ## Copyright (C) 2010 Soren Hauberg <soren@hauberg.org> |
393 | 2 ## |
561
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
3 ## This program is free software; you can redistribute it and/or modify it under |
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
4 ## the terms of the GNU General Public License as published by the Free Software |
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
5 ## Foundation; either version 3 of the License, or (at your option) any later |
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
6 ## version. |
393 | 7 ## |
561
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
8 ## This program is distributed in the hope that it will be useful, but WITHOUT |
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
9 ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
10 ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
11 ## details. |
393 | 12 ## |
561
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
13 ## You should have received a copy of the GNU General Public License along with |
c45838839d86
maint: update license to GPLv3 and mention non GPL files
carandraug
parents:
396
diff
changeset
|
14 ## this program; if not, see <http://www.gnu.org/licenses/>. |
393 | 15 |
16 ## -*- texinfo -*- | |
17 ## @deftypefn {Function File} {@var{props} = } regionprops (@var{BW}) | |
18 ## @deftypefnx {Function File} {@var{props} = } regionprops (@var{BW}, @var{properties}, @dots{}) | |
19 ## Compute object properties in a binary image. | |
20 ## | |
21 ## @code{regionprops} computes various properties of the individual objects (as | |
22 ## identified by @code{bwlabel}) in the binary image @var{BW}. The result is a | |
23 ## structure array containing an entry per property per object. | |
24 ## | |
25 ## The following properties can be computed. | |
26 ## | |
27 ## @table @t | |
28 ## @item "Area" | |
29 ## The number of pixels in the object. | |
30 ## @item "EulerNumber" | |
31 ## @itemx "euler_number" | |
32 ## The Euler number of the object (see @code{bweuler} for details). | |
33 ## @item "BoundingBox" | |
34 ## @itemx "bounding_box" | |
35 ## The bounding box of the object. This is represented as a 4-vector where the | |
36 ## first two entries are the @math{x} and @math{y} coordinates of the upper left | |
37 ## corner of the bounding box, and the two last entries are the width and the | |
38 ## height of the box. | |
39 ## @item "Extent" | |
40 ## The area of the object divided by the area of the bounding box. | |
41 ## @item "Perimeter" | |
42 ## The length of the boundary of the object. | |
43 ## @item "Centroid" | |
44 ## The center coordinate of the object. | |
45 ## @item "PixelIdxList" | |
46 ## @itemx "pixel_idx_list" | |
47 ## The indices of the pixels in the object. | |
48 ## @item "FilledArea" | |
49 ## @itemx "filled_area" | |
50 ## The area of the object including possible holes. | |
51 ## @item "PixelList" | |
52 ## @itemx "pixel_list" | |
53 ## The actual pixel values inside the object. This is only useful for grey scale | |
54 ## images. | |
55 ## @item "FilledImage" | |
56 ## @itemx "filled_image" | |
57 ## A binary image with the same size as the object's bounding box that contains | |
58 ## the object with all holes removed. | |
59 ## @item "Image" | |
60 ## An image with the same size as the bounding box that contains the original pixels. | |
61 ## @item "MaxIntensity" | |
62 ## @itemx "max_intensity" | |
63 ## The maximum intensity inside the object. | |
64 ## @item "MinIntensity" | |
65 ## @itemx "min_intensity" | |
66 ## The minimum intensity inside the object. | |
67 ## @item "WeightedCentroid" | |
68 ## @itemx "weighted_centroid" | |
69 ## The centroid of the object where pixel values are used as weights. | |
70 ## @item "MeanIntensity" | |
71 ## @itemx "mean_intensity" | |
72 ## The mean intensity inside the object. | |
73 ## @item "PixelValues" | |
74 ## @itemx "pixel_values" | |
75 ## The pixel values inside the object represented as a vector. | |
76 ## @end table | |
77 ## | |
78 ## The requested properties can either be specified as several input arguments | |
79 ## or as a cell array of strings. As a short-hand it is also possible to give | |
80 ## the following strings as arguments. | |
81 ## | |
82 ## @table @t | |
83 ## @item "basic" | |
84 ## The following properties are computed: @t{"Area"}, @t{"Centroid"} and @t{"BoundingBox"}. | |
85 ## @item "all" | |
86 ## All properties are computed. | |
87 ## @end table | |
88 ## | |
89 ## If no properties are given, @t{basic} is assumed. | |
90 ## @seealso{bwlabel, bwperim, bweuler} | |
91 ## @end deftypefn | |
92 | |
93 function retval = regionprops (bw, varargin) | |
94 ## Check input | |
95 if (nargin < 1) | |
96 error ("regionprops: not enough input arguments"); | |
97 endif | |
98 | |
99 if (!ismatrix (bw) || ndims (bw) != 2) | |
100 error ("regionprops: first input argument must be a NxM matrix"); | |
101 endif | |
102 | |
103 if (numel (varargin) == 0) | |
104 properties = "basic"; | |
105 elseif (numel (varargin) == 1 && iscellstr (varargin {1})) | |
106 properties = varargin {1}; | |
107 elseif (iscellstr (varargin)) | |
108 properties = varargin; | |
109 else | |
110 error ("regionprops: properties must be a cell array of strings"); | |
111 endif | |
112 | |
113 if (ischar (properties) && strcmpi (properties, "basic")) | |
114 properties = {"Area", "Centroid", "BoundingBox"}; | |
115 elseif (ischar (properties) && strcmpi (properties, "all")) | |
116 properties = {"area", "eulernumber", "boundingbox", "extent", "perimeter", ... | |
117 "centroid", "pixelidxlist", "filledarea", "pixellist", ... | |
118 "filledimage", "image", "maxintensity", "minintensity", ... | |
119 "weightedcentroid", "meanintensity", "pixelvalues"}; | |
120 elseif (!iscellstr (properties)) | |
121 error ("%s %s", "regionprops: properties must be specified as a list of", | |
122 "strings or a cell array of strings"); | |
123 endif | |
124 | |
125 ## Get a labelled image | |
126 if (!islogical (bw) && all (bw >= 0) && all (bw == round (bw))) | |
127 L = bw; # the image was already labelled | |
128 num_labels = max (L (:)); | |
129 else | |
396 | 130 [L, num_labels] = bwlabel (bw); |
393 | 131 endif |
132 | |
133 ## Compute the properties | |
134 retval = struct (); | |
135 for k = 1:numel (properties) | |
136 switch (lower (properties {k})) | |
137 case "area" | |
138 for k = 1:num_labels | |
139 retval (k).Area = local_area (L == k); | |
140 endfor | |
141 | |
142 case {"eulernumber", "euler_number"} | |
143 for k = 1:num_labels | |
144 retval (k).EulerNumber = bweuler (L == k); | |
145 endfor | |
146 | |
147 case {"boundingbox", "bounding_box"} | |
148 for k = 1:num_labels | |
149 retval (k).BoundingBox = local_boundingbox (L == k); | |
150 endfor | |
151 | |
152 case "extent" | |
153 for k = 1:num_labels | |
154 bb = local_boundingbox (L == k); | |
155 area = local_area (L == k); | |
156 retval (k).Extent = area / (bb (3) * bb (4)); | |
157 endfor | |
158 | |
159 case "perimeter" | |
160 for k = 1:num_labels | |
161 retval (k).Perimeter = sum (bwperim (L == k) (:)); | |
162 endfor | |
163 | |
164 case "centroid" | |
165 for k = 1:num_labels | |
166 [Y, X] = find (L == k); | |
167 retval (k).Centroid = [mean(X), mean(Y)]; | |
168 endfor | |
169 | |
170 case {"pixelidxlist", "pixel_idx_list"} | |
171 for k = 1:num_labels | |
172 retval (k).PixelIdxList = find (L == k); | |
173 endfor | |
174 | |
175 case {"filledarea", "filled_area"} | |
176 for k = 1:num_labels | |
177 retval (k).FilledArea = sum (bwfill (L == k, "holes") (:)); | |
178 endfor | |
179 | |
180 case {"pixellist", "pixel_list"} | |
181 for k = 1:num_labels | |
182 [Y, X] = find (L == k); | |
183 retval (k).PixelList = [X, Y]; | |
184 endfor | |
185 | |
186 case {"filledimage", "filled_image"} | |
187 for k = 1:num_labels | |
188 retval (k).FilledImage = bwfill (L == k, "holes"); | |
189 endfor | |
190 | |
191 case "image" | |
192 for k = 1:num_labels | |
193 tmp = (L == k); | |
194 [R, C] = find (tmp); | |
195 retval (k).Image = tmp (min (R):max (R), min (C):max (C)); | |
196 endfor | |
197 | |
198 case {"maxintensity", "max_intensity"} | |
199 for k = 1:num_labels | |
200 retval (k).MaxIntensity = max (bw (L == k) (:)); | |
201 endfor | |
202 | |
203 case {"minintensity", "min_intensity"} | |
204 for k = 1:num_labels | |
205 retval (k).MaxIntensity = min (bw (L == k) (:)); | |
206 endfor | |
207 | |
208 case {"weightedcentroid", "weighted_centroid"} | |
209 for k = 1:num_labels | |
210 [Y, X] = find (L == k); | |
211 vals = bw (L == k) (:); | |
212 vals /= sum (vals); | |
213 retval (k).WeightedCentroid = [dot(X, vals), dot(Y, vals)]; | |
214 endfor | |
215 | |
216 case {"meanintensity", "mean_intensity"} | |
217 for k = 1:num_labels | |
218 retval (k).MaxIntensity = mean (bw (L == k) (:)); | |
219 endfor | |
220 | |
221 case {"pixelvalues", "pixel_values"} | |
222 for k = 1:num_labels | |
223 retval (k).PixelValues = bw (L == k)(:); | |
224 endfor | |
225 | |
396 | 226 case "orientation" |
227 for k = 1:num_labels | |
228 [Y, X] = find (L == k); | |
229 if (numel (Y) > 1) | |
230 C = cov ([X(:), Y(:)]); | |
231 [V, lambda] = eig (C); | |
232 [max_val, max_idx] = max (diag (lambda)); | |
233 v = V (:, max_idx); | |
234 retval (k).Orientation = 180 - 180 * atan2 (v (2), v (1)) / pi; | |
235 else | |
236 retval (k).Orientation = 0; # XXX: What does the other brand do? | |
237 endif | |
238 endfor | |
239 | |
240 %{ | |
241 case "majoraxislength" | |
242 for k = 1:num_labels | |
243 [Y, X] = find (L == k); | |
244 if (numel (Y) > 1) | |
245 C = cov ([X(:), Y(:)]); | |
246 lambda = eig (C); | |
247 retval (k).MajorAxisLength = (max (lambda)); | |
248 else | |
249 retval (k).MajorAxisLength = 1; | |
250 endif | |
251 endfor | |
252 | |
253 case "minoraxislength" | |
254 for k = 1:num_labels | |
255 [Y, X] = find (L == k); | |
256 if (numel (Y) > 1) | |
257 C = cov ([X(:), Y(:)]); | |
258 lambda = eig (C); | |
259 retval (k).MinorAxisLength = (min (lambda)); | |
260 else | |
261 retval (k).MinorAxisLength = 1; | |
262 endif | |
263 endfor | |
264 %} | |
265 | |
393 | 266 #case "extrema" |
267 #case "convexarea" | |
268 #case "convexhull" | |
269 #case "solidity" | |
270 #case "conveximage" | |
271 #case "subarrayidx" | |
272 #case "eccentricity" | |
273 #case "equivdiameter" | |
274 | |
275 otherwise | |
276 error ("regionprops: unsupported property '%s'", properties {k}); | |
277 endswitch | |
278 endfor | |
279 endfunction | |
280 | |
281 function retval = local_area (bw) | |
282 retval = sum (bw (:)); | |
283 endfunction | |
284 | |
285 function retval = local_boundingbox (bw) | |
286 [Y, X] = find (bw); | |
287 retval = [min(X)-0.5, min(Y)-0.5, max(X)-min(X)+1, max(Y)-min(Y)+1]; | |
288 endfunction |