1## Copyright (C) 2014 Carnë Draug <carandraug@octave.org> 2## 3## This program is free software; you can redistribute it and/or 4## modify it under the terms of the GNU General Public License as 5## published by the Free Software Foundation; either version 3 of the 6## License, or (at your option) any later version. 7## 8## This program is distributed in the hope that it will be useful, but 9## WITHOUT ANY WARRANTY; without even the implied warranty of 10## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11## 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 15## <http:##www.gnu.org/licenses/>. 16 17## -*- texinfo -*- 18## @deftypefn {Function File} {} bwpropfilt (@var{bw}, @var{attrib}) 19## @deftypefnx {Function File} {} bwpropfilt (@var{bw}, @var{I}, @var{attrib}) 20## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @var{range}) 21## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @var{n}) 22## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @var{n}, @var{keep}) 23## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @dots{}, @var{conn}) 24## Filter objects from image based on their properties. 25## 26## Returns a logical matrix with the objects of @var{bw} filtered based 27## on the specific property @var{attrib}. The possible values for @var{attrib} 28## are all the properties from @command{regionprops} that return a scalar 29## value, e.g., Area, Extent, and MaxIntensity, but not PixelValues, basic, and 30## BoundingBox. For certain attributes, such as MaxIntensity and 31## WeightedCentroid, the grayscale image @var{I} must also be specified. 32## 33## To filter objects with a value on a specific interval, @var{range} must be 34## a two-element vector with the interval @code{[@var{low} @var{high}]} 35## (values are inclusive). 36## 37## Alternatively, a scalar @var{n} will select the objects with the N highest 38## values. The @var{keep} option defaults to @qcode{"largest"} but can also 39## be set to @qcode{"smallest"} to select the N objects with lower values. 40## 41## The last optional argument, @var{conn}, can be a connectivity matrix, or 42## the number of elements connected to the center (see @command{conndef}). 43## 44## @seealso{bwareaopen, bwareafilt, bwlabel, bwlabeln, bwconncomp, regionprops} 45## @end deftypefn 46 47function bwfiltered = bwpropfilt (bw, varargin) 48 if (nargin < 3 || nargin > 6) 49 print_usage (); 50 endif 51 52 if (ischar (varargin{1})) 53 no_gray = true; 54 attrib = varargin{1}; 55 next_idx = 2; 56 else 57 no_gray = false; 58 img = varargin{1}; 59 attrib = varargin{2}; 60 next_idx = 3; 61 endif 62 63 valid_nargin = @(x) numel (varargin) >= x; 64 65 if (isscalar (varargin{next_idx})) 66 ## Get the N largest or smallest 67 in_range = false; 68 n_keep = varargin{next_idx}; 69 next_idx++; 70 71 if (valid_nargin (next_idx) && ischar (varargin{next_idx})) 72 keep = tolower (varargin{next_idx}); 73 if (! any (strcmpi (keep, {"largest", "smallest"}))) 74 error ("bwpropfilt: KEEP must be `largest' or `smallest'"); 75 endif 76 next_idx++; 77 else 78 keep = "largest"; 79 endif 80 81 elseif (numel (varargin{next_idx}) == 2) 82 in_range = true; 83 range = varargin{next_idx}; 84 next_idx++; 85 else 86 error ("bwpropfilt: N and RANGE must have 1 or 2 elements respectively"); 87 endif 88 89 if (valid_nargin (next_idx)) 90 conn = conndef (varargin{next_idx++}); 91 92 if (valid_nargin (next_idx)) 93 print_usage (); 94 endif 95 else 96 ## Non-documented default 97 conn = conndef (ndims (bw), "maximal"); 98 endif 99 100 cc = bwconncomp (bw, conn); 101 if (no_gray) 102 stats = regionprops (cc, {"PixelIdxList", attrib}); 103 else 104 stats = regionprops (cc, img, {"PixelIdxList", attrib}); 105 endif 106 107 n_objs = numel (stats); 108 idxs = {stats.PixelIdxList}; 109 attribs = [stats.(attrib)]; 110 111 if (in_range) 112 filtered_idxs = idxs(attribs >= range(1) & attribs <= range(2)); 113 else 114 [~, sorted_idxs] = sort (attribs, "descend"); 115 switch (keep) 116 case "largest", 117 filtered_idxs = idxs(sorted_idxs(1:min (n_keep, n_objs))); 118 case "smallest", 119 filtered_idxs = idxs(sorted_idxs(max (1, n_objs - n_keep +1):end)); 120 endswitch 121 endif 122 123 bwfiltered = false (size (bw)); 124 bwfiltered(cat (1, filtered_idxs{:})(:)) = true; 125 126endfunction 127 128