]> Creatis software - CreaPhase.git/blob - octave_packages/image-1.0.15/regionprops.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / image-1.0.15 / regionprops.m
1 ## Copyright (C) 2010 Soren Hauberg
2 ##
3 ## This program is free software; you can redistribute it and/or modify
4 ## it under the terms of the GNU General Public License as published by
5 ## the Free Software Foundation; either version 3 of the License, or
6 ## (at your option) any later version.
7 ##
8 ## This program is distributed in the hope that it will be useful,
9 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 ## GNU General Public License for more details.
12 ##
13 ## You should have received a copy of the GNU General Public License
14 ## along with this program; If not, see <http://www.gnu.org/licenses/>.
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
130     [L, num_labels] = bwlabel (bw);
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     
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       
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
289