1## Copyright (C) 2008 Søren Hauberg <soren@hauberg.org>
2##
3## This program is free software; you can redistribute it and/or modify it under
4## the terms of the GNU General Public License as published by the Free Software
5## Foundation; either version 3 of the License, or (at your option) any later
6## version.
7##
8## This program is distributed in the hope that it will be useful, but WITHOUT
9## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11## details.
12##
13## You should have received a copy of the GNU General Public License along with
14## this program; if not, see <http://www.gnu.org/licenses/>.
15
16## -*- texinfo -*-
17## @deftypefn  {Function File} {} ordfiltn (@var{A}, @var{nth}, @var{domain})
18## @deftypefnx {Function File} {} ordfiltn (@var{A}, @var{nth}, @var{domain}, @var{S})
19## @deftypefnx {Function File} {} ordfiltn (@dots{}, @var{padding})
20## N dimensional ordered filtering.
21##
22## Ordered filter replaces an element of @var{A} with the @var{nth} element
23## element of the sorted set of neighbours defined by the logical
24## (boolean) matrix @var{domain}.
25## Neighbour elements are selected to the sort if the corresponding
26## element in the @var{domain} matrix is true.
27##
28## The optional variable @var{S} is a matrix of size(@var{domain}).
29## Values of @var{S} corresponding to nonzero values of domain are
30## added to values obtained from @var{A} when doing the sorting.
31##
32## Optional variable @var{padding} determines how the matrix @var{A}
33## is padded from the edges. See @code{padarray} for details.
34##
35## @seealso{medfilt2, padarray, ordfilt2}
36## @end deftypefn
37
38## This function is based on 'ordfilt2' by Teemu Ikonen <tpikonen@pcu.helsinki.fi>
39## which is released under GPLv2 or later.
40
41function retval = ordfiltn (A, nth, domain, varargin)
42
43  ## Check input
44  if (nargin < 3)
45    print_usage ();
46  elseif (! isnumeric (A) && ! islogical (A))
47    error ("ordfiltn: A must be a numeric or logical array");
48  elseif (! isscalar (nth) || nth <= 0 || fix (nth) != nth)
49    error ("ordfiltn: second input argument must be a positive integer");
50  elseif (! isnumeric (domain) && ! islogical (domain))
51    error ("ordfiltn: DOMAIN must be a numeric or logical array or scalar");
52  elseif (isscalar (domain) && (domain <= 0 || fix (domain) != domain))
53    error ("ordfiltn: third input argument must be a positive integer, when it is a scalar");
54  endif
55
56  if (isscalar (domain))
57    domain = true (repmat (domain, 1, ndims (A)));
58  endif
59
60  if (ndims (A) != ndims (domain))
61    error ("ordfiltn: first and second argument must have same dimensionality");
62  elseif (any (size (A) < size (domain)))
63    error ("ordfiltn: domain array cannot be larger than the data array");
64  endif
65
66  ## Parse varargin
67  S = zeros (size (domain));
68  padding = 0;
69  for idx = 1:length(varargin)
70    opt = varargin{idx};
71    if (ischar (opt) || isscalar (opt))
72      padding = opt;
73    elseif (isnumeric (opt) && size_equal (opt, domain))
74      S = opt;
75    else
76      error ("ordfiltn: unrecognized option from input argument #%i and class %s", 3 + idx, class (opt));
77    endif
78  endfor
79
80  A = pad_for_sliding_filter (A, size (domain), padding);
81
82  ## Perform the filtering
83  retval = __spatial_filtering__ (A, logical (domain), "ordered", S, nth);
84
85endfunction
86
87%!shared b, f, s
88%! b = [ 0  1  2  3
89%!       1  8 12 12
90%!       4 20 24 21
91%!       7 22 25 18];
92%!
93%! f = [ 8 12 12 12
94%!      20 24 24 24
95%!      22 25 25 25
96%!      22 25 25 25];
97%!assert (ordfiltn (b, 9, true (3)), f);
98%!
99%! f = [ 1  8 12 12
100%!       8 20 21 21
101%!      20 24 24 24
102%!      20 24 24 24];
103%!assert (ordfiltn (b, 8, true (3)), f);
104%!
105%! f = [ 1  2  8 12
106%!       4 12 20 21
107%!       8 22 22 21
108%!      20 24 24 24];
109%!assert (ordfiltn (b, 7, true (3), "symmetric"), f);
110%!
111%! f = [ 1  8 12 12
112%!       4 20 24 21
113%!       7 22 25 21
114%!       7 22 25 21];
115%!assert (ordfiltn (b, 3, true (3, 1)), f);
116%!
117%! f = [ 1  8 12 12
118%!       4 20 24 18
119%!       4 20 24 18
120%!       4 20 24 18];
121%!assert (ordfiltn (b, 3, true (4, 1)), f);
122%!
123%! f = [ 4 20 24 21
124%!       7 22 25 21
125%!       7 22 25 21
126%!       7 22 25 21];
127%!assert (ordfiltn (b, 4, true (4, 1)), f);
128%!
129%! s = [0 0 1
130%!      0 0 1
131%!      0 0 1];
132%! f = [ 2  8 12 12
133%!       9 20 22 21
134%!      21 25 24 24
135%!      21 25 24 24];
136%!assert (ordfiltn (b, 8, true (3), s), f);
137%!
138%! b(:,:,2) = b(:,:,1) - 1;
139%! b(:,:,3) = b(:,:,2) - 1;
140%! f(:,:,1) = [ 1  8 11 11
141%!              8 20 21 21
142%!              20 24 24 24
143%!              20 24 24 24];
144%! f(:,:,2) = [ 6 10 11 11
145%!             18 22 22 22
146%!             20 24 24 24
147%!             20 24 24 24];
148%! f(:,:,3) = [ 0  7 10 10
149%!              7 19 20 20
150%!             19 23 23 23
151%!             19 23 23 23];
152%!assert (ordfiltn (b, 25, true (3, 3, 3)), f);
153