Mercurial > hg > octave-image
changeset 909:ba9e0f8a25c0
New functions bwareafilt and bwpropfilt to filter objects based on properties.
* bwpropfilt.m: new function file which filters objects from binary image
based on multiple properties available from regionprops.
* bwareafilt.m: wrapper to bwpropfilt, specific to Area.
* COPYING, INDEX, NEWS: add new functions to all the lists.
author | Carnë Draug <carandraug@octave.org> |
---|---|
date | Mon, 27 Oct 2014 22:07:52 +0100 |
parents | f53cc3aaa88e |
children | cda9868e7641 |
files | COPYING INDEX NEWS inst/bwareafilt.m inst/bwpropfilt.m |
diffstat | 5 files changed, 389 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/COPYING +++ b/COPYING @@ -31,6 +31,7 @@ inst/bestblk.m GPLv3+ inst/blockproc.m GPLv3+ inst/bwarea.m GPLv3+ +inst/bwareafilt.m GPLv3+ inst/bwareaopen.m GPLv3+ inst/bwboundaries.m GPLv3+ inst/bwconncomp.m GPLv3+ @@ -39,6 +40,7 @@ inst/bwhitmiss.m GPLv3+ inst/bwmorph.m GPLv3+ inst/bwperim.m GPLv3+ +inst/bwpropfilt.m GPLv3+ inst/bwselect.m GPLv3+ inst/col2im.m GPLv3+ inst/colfilt.m GPLv3+
--- a/INDEX +++ b/INDEX @@ -33,6 +33,7 @@ Black and white image functions applylut bwarea + bwareafilt bwboundaries bwconncomp bwdist @@ -43,6 +44,7 @@ bwlabeln bwmorph bwperim + bwpropfilt bwselect fchcode labelmatrix
--- a/NEWS +++ b/NEWS @@ -3,6 +3,8 @@ ** The following functions are new: + bwareafilt + bwpropfilt imcast ** The implementation of normxcorr2 has been changed. The new method is
new file mode 100644 --- /dev/null +++ b/inst/bwareafilt.m @@ -0,0 +1,247 @@ +## Copyright (C) 2014 Carnë Draug <carandraug@octave.org> +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License as +## published by the Free Software Foundation; either version 3 of the +## License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see +## <http:##www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {} bwareafilt (@var{bw}, @var{range}) +## @deftypefnx {Function File} {} bwareafilt (@var{bw}, @var{n}) +## @deftypefnx {Function File} {} bwareafilt (@var{bw}, @var{n}, @var{keep}) +## @deftypefnx {Function File} {} bwareafilt (@dots{}, @var{conn}) +## Filter objects from image based on their sizes. +## +## Returns a logical matrix with the objects of @var{bw} filtered based +## on their area (defined by thei number of pixels). This function is +## equivalent to @code{bwpropfilt (@var{bw}, "Area", @dots{})}. +## +## To filter objects with a value on a specific interval, @var{range} must be +## a two-element vector with the interval @code{[@var{low} @var{high}]} +## (values are inclusive). +## +## Alternatively, a scalar @var{n} will select the objects with the N highest +## values. The @var{keep} option defaults to @qcode{"largest"} but can also +## be set to @qcode{"smallest"} to select the N objects with lower values. +## +## The last optional argument, @var{conn}, can be a connectivity matrix, or +## the number of elements connected to the center (see @command{conndef}). +## +## @seealso{bwareaopen, bwlabel, bwlabeln, bwconncomp, bwpropfilt, regionprops} +## @end deftypefn + +function bwfiltered = bwareafilt (bw, varargin) + if (nargin < 2 || nargin > 4) + print_usage (); + endif + bwfiltered = bwpropfilt (bw, "Area", varargin{:}); +endfunction + +%!shared a2d, a3d +%! a2d = [1 0 0 0 0 0 1 0 0 1 +%! 1 0 0 1 0 1 0 1 0 1 +%! 1 0 1 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 0 0 0 +%! 1 1 0 1 1 1 0 0 0 0 +%! 1 1 0 1 0 0 0 1 0 0 +%! 1 1 0 0 0 0 1 0 1 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 1 1 0 0 1]; +%! +%! a3d = a2d; +%! a3d(:,:,2) = [ +%! 0 0 0 0 0 0 0 0 0 0 +%! 1 0 0 1 1 0 0 1 0 0 +%! 0 0 0 1 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 1 1 0 0 0 0 +%! 1 1 0 1 0 0 0 0 0 0 +%! 1 0 0 0 0 0 1 0 0 0 +%! 0 1 0 0 0 0 0 0 0 1 +%! 1 1 0 0 0 0 1 0 0 0]; +%! +%! a3d(:,:,3) = [ +%! 1 0 0 0 0 0 0 0 0 0 +%! 0 1 0 1 1 0 0 1 0 0 +%! 0 0 0 1 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 1 1 1 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 1 0 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 1 +%! 1 1 0 0 0 0 0 0 0 0]; + +%!test +%! f2d = [0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 0 0 0 +%! 1 1 0 1 1 1 0 0 0 0 +%! 1 1 0 1 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0]; +%! assert (bwareafilt (a2d, 2), logical (f2d)); +%! assert (bwareafilt (a2d, 2, 8), logical (f2d)); +%! assert (bwareafilt (a2d, 2, 4), logical (f2d)); + +%!test +%! f2d = [1 0 0 0 0 0 1 0 0 0 +%! 1 0 0 0 0 1 0 1 0 0 +%! 1 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 0 0 0 +%! 1 1 0 1 1 1 0 0 0 0 +%! 1 1 0 1 0 0 0 1 0 0 +%! 1 1 0 0 0 0 1 0 1 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0]; +%! assert (bwareafilt (a2d, 5), logical (f2d)); +%! assert (bwareafilt (a2d, 5, 8), logical (f2d)); + +%!test +%! f2d = [0 0 0 0 0 0 1 0 0 1 +%! 0 0 0 1 0 1 0 1 0 1 +%! 0 0 1 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 1 0 0 +%! 0 0 0 0 0 0 1 0 1 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 1 1 0 0 1]; +%! assert (bwareafilt (a2d, 11, "smallest", 4), logical (f2d)); + +%!test +%! f2d = [1 0 0 0 0 0 1 0 0 0 +%! 1 0 0 0 0 1 0 1 0 0 +%! 1 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 1 1 1 0 0 0 0 +%! 0 0 0 1 0 0 0 1 0 0 +%! 0 0 0 0 0 0 1 0 1 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0]; +%! assert (bwareafilt (a2d, [3 5]), logical (f2d)); +%! assert (bwareafilt (a2d, [3 5], 8), logical (f2d)); + +%!test +%! f2d = [1 0 0 0 0 0 0 0 0 0 +%! 1 0 0 0 0 0 0 0 0 0 +%! 1 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 1 1 1 0 0 0 0 +%! 0 0 0 1 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0]; +%! assert (bwareafilt (a2d, [3 4], 4), logical (f2d)); +%! assert (bwareafilt (a2d, [3 4], [0 1 0; 1 1 1; 0 1 0]), logical (f2d)); + +%!test +%! f2d = [1 0 0 0 0 0 1 0 0 1 +%! 1 0 0 1 0 1 0 1 0 1 +%! 1 0 1 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 1 1 1 0 0 0 0 +%! 0 0 0 1 0 0 0 1 0 0 +%! 0 0 0 0 0 0 1 0 1 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 1 1 0 0 0]; +%! assert (bwareafilt (a2d, [2 4]), logical (f2d)); +%! assert (bwareafilt (a2d, [2 4], 8), logical (f2d)); +%! assert (bwareafilt (a2d, [2 4], ones (3)), logical (f2d)); + +%!test +%! f3d = [0 0 0 0 0 0 1 0 0 0 +%! 0 0 0 1 0 1 0 1 0 0 +%! 0 0 1 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0]; +%! +%! f3d(:,:,2) = [ +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 1 1 0 0 1 0 0 +%! 0 0 0 1 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 0 0 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0]; +%! +%! f3d(:,:,3) = [ +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 1 1 0 0 1 0 0 +%! 0 0 0 1 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 1 0 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0]; +%! assert (bwareafilt (a3d, 2), logical (f3d)); +%! assert (bwareafilt (a3d, 2, 26), logical (f3d)); +%! assert (bwareafilt (a3d, 2, ones (3, 3, 3)), logical (f3d)); + +%!test +%! f3d = [0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 0 0 0 +%! 1 1 0 1 1 1 0 0 0 0 +%! 1 1 0 1 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0]; +%! +%! f3d(:,:,2) = [ +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 1 1 0 0 0 0 +%! 1 1 0 1 0 0 0 0 0 0 +%! 1 0 0 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0]; +%! +%! f3d(:,:,3) = [ +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 0 0 0 1 1 1 0 0 0 0 +%! 0 0 0 0 0 0 0 0 0 0 +%! 1 0 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0 +%! 1 1 0 0 0 0 0 0 0 0]; +%! assert (bwareafilt (a3d, 2, 6), logical (f3d)); +%! assert (bwareafilt (a3d, 2, conndef (3, "minimal")), logical (f3d)); +
new file mode 100644 --- /dev/null +++ b/inst/bwpropfilt.m @@ -0,0 +1,136 @@ +## Copyright (C) 2014 Carnë Draug <carandraug@octave.org> +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License as +## published by the Free Software Foundation; either version 3 of the +## License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see +## <http:##www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {} bwpropfilt (@var{bw}, @var{attrib}) +## @deftypefnx {Function File} {} bwpropfilt (@var{bw}, @var{I}, @var{attrib}) +## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @var{range}) +## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @var{n}) +## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @var{n}, @var{keep}) +## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @dots{}, @var{conn}) +## Filter objects from image based on their properties. +## +## Returns a logical matrix with the objects of @var{bw} filtered based +## on the specific property @var{attrib}. The possible values for @var{attrib} +## are all the properties from @command{regionprops} that return a scalar +## value, e.g., Area, Extent, and MaxIntensity, but not PixelValues, basic, and +## BoundingBox. For certain attributes, such as MaxIntensity and +## WeightedCentroid, the grayscale image @var{I} must also be specified. +## +## To filter objects with a value on a specific interval, @var{range} must be +## a two-element vector with the interval @code{[@var{low} @var{high}]} +## (values are inclusive). +## +## Alternatively, a scalar @var{n} will select the objects with the N highest +## values. The @var{keep} option defaults to @qcode{"largest"} but can also +## be set to @qcode{"smallest"} to select the N objects with lower values. +## +## The last optional argument, @var{conn}, can be a connectivity matrix, or +## the number of elements connected to the center (see @command{conndef}). +## +## @seealso{bwareaopen, bwareafilt, bwlabel, bwlabeln, bwconncomp, regionprops} +## @end deftypefn + +function bwfiltered = bwpropfilt (bw, varargin) + if (nargin < 3 || nargin > 6) + print_usage (); + endif + + if (ischar (varargin{1})) + no_gray = true; + attrib = varargin{1}; + next_idx = 2; + else + no_gray = false; + img = varargin{1}; + attrib = varargin{2}; + next_idx = 3; + endif + + valid_nargin = @(x) numel (varargin) >= x; + + if (isscalar (varargin{next_idx})) + ## Get the N largest or smallest + in_range = false; + n_keep = varargin{next_idx}; + next_idx++; + + if (valid_nargin (next_idx) && ischar (varargin{next_idx})) + keep = tolower (varargin{next_idx}); + if (! any (strcmpi (keep, {"largest", "smallest"}))) + error ("bwpropfilt: KEEP must be `largest' or `smallest'"); + endif + next_idx++; + else + keep = "largest"; + endif + + elseif (numel (varargin{next_idx}) == 2) + in_range = true; + range = varargin{next_idx}; + next_idx++; + else + error ("bwpropfilt: N and RANGE must have 1 or 2 elements respectively"); + endif + + if (valid_nargin (next_idx)) + conn = varargin{next_idx}; + try + iptcheckconn (conn, "bwpropfilt", "CONN"); + catch + conn = conndef (conn); + end_try_catch + + next_idx++; + if (valid_nargin (next_idx)) + print_usage (); + endif + else + ## Non-documented default + conn = conndef (ndims (bw), "maximal"); + endif + + ## FIXME: we need to call bwconncomp with our specific connectivity and + ## then pass its struct to regionprops. That may be faster but is + ## not yet implemented so we call labelmatrix + labeled = labelmatrix (bwconncomp (bw, conn)); + if (no_gray) + stats = regionprops (labeled, {"PixelIdxList", attrib}); + else + stats = regionprops (labeled, img, {"PixelIdxList", attrib}); + endif + + n_objs = numel (stats); + idxs = {stats.PixelIdxList}; + attribs = [stats.(attrib)]; + + if (in_range) + filtered_idxs = idxs(attribs >= range(1) & attribs <= range(2)); + else + [~, sorted_idxs] = sort (attribs, "descend"); + switch (keep) + case "largest", + filtered_idxs = idxs(sorted_idxs(1:min (n_keep, n_objs))); + case "smallest", + filtered_idxs = idxs(sorted_idxs(max (1, n_objs - n_keep +1):end)); + endswitch + endif + + bwfiltered = false (size (bw)); + bwfiltered(cat (1, filtered_idxs{:})(:)) = true; + +endfunction +