/usr/share/octave/packages/image-2.2.2/nlfilter.m is in octave-image 2.2.2-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | ## Copyright (C) 2013 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} {} nlfilter (@var{A}, @var{block_size}, @var{func})
## @deftypefnx {Function File} {} nlfilter (@var{A}, @var{block_size}, @var{func}, @dots{})
## @deftypefnx {Function File} {} nlfilter (@var{A}, "indexed", @dots{})
## Process matrix in sliding blocks with user-supplied function.
##
## Executes the function @var{fun} on each sliding block of
## size @var{block_size}, taken from the matrix @var{A}. Both the matrix
## @var{A}, and the block can have any number of dimensions. This function
## is specially useful to perform sliding/moving window functions such as
## moving average.
##
## The output will have the same dimensions @var{A}, each one of its values
## corresponding to the processing of a block centered at the same
## coordinates in @var{A}, with @var{A} being padded with zeros for the
## borders (see below for indexed images). In case any side of the block
## is of even length, the center is considered at indices
## @code{floor ([@var{block_size}/2] + 1)}.
##
## The argument @var{func} must be a function handle that takes matrices of
## size @var{block_size} as input and returns a single scalar. Any extra
## input arguments to @code{nlfilter} are passed to @var{func} after the
## block matrix.
##
## If @var{A} is an indexed image, the second argument should be the
## string @qcode{"indexed"} so that any required padding is done correctly
## as done by @code{im2col}.
##
## @emph{Note}: if @var{func} is a column compression function, i.e., it acts
## along a column to return a single value, consider using @code{colfilt}
## which usually performs faster. If @var{func} makes use of the colon
## operator to select all elements in the block, e.g., if @var{func} looks
## anything like @code{@@(x) sum (x(:))}, it is a good indication that
## @code{colfilt} should be used. In addition, many sliding block operations
## have their own specific implementations (see help text of @code{colfilt}
## for a list).
##
## @seealso{blockproc, col2im, colfilt, im2col}
## @end deftypefn
function B = nlfilter (A, varargin)
## Input check
[p, block_size, padval] = im2col_check ("nlfilter", nargin, A, varargin{:});
if (nargin < p)
print_usage ();
endif
func = varargin{p++};
if (! isa (func, "function_handle"))
error ("nlfilter: FUNC must be a function handle");
elseif (! isscalar (func (ones (block_size, class (A)), varargin{p:nargin-1})))
error ("nlfilter: FUNC must take a matrix of size BLOCK_SIZE and return a scalar");
endif
## Remaining params are parameters to fun. We need to place them into
## a separate variable, we can't varargin{p:nargin-1} inside the anonymous
## function because nargin will have a different value there
extra_args = varargin(p:nargin -1);
## Pad image as required
padded = pad_for_sliding_filter (A, block_size, padval);
## Get the blocks (one per column)
blks = im2col (padded, block_size, "sliding");
## New function that reshapes the array into a block before
## passing it to the actual user supplied function
blk_func = @(x, z) func (reshape (blks(x:z), block_size), extra_args{:});
## Perform the filtering
blk_step = 1:(rows (blks)):(rows (blks) * columns (blks));
B = arrayfun (blk_func, blk_step, blk_step + rows (blks) -1);
## Back into its original shape
B = reshape (B, size (A));
endfunction
%!demo
%! ## creates a "wide" diagonal (although it can be performed more
%! ## efficiently with "imdilate (A, true (3))")
%! nlfilter (eye (10), [3 3], @(x) any (x(:) > 0))
%!assert (nlfilter (eye (4), [2 3], @(x) sum (x(:))),
%! [2 2 1 0
%! 1 2 2 1
%! 0 1 2 2
%! 0 0 1 1]);
%!assert (nlfilter (eye (4), "indexed", [2 3], @(x) sum (x(:))),
%! [4 2 1 2
%! 3 2 2 3
%! 2 1 2 4
%! 4 3 4 5]);
%!assert (nlfilter (eye (4), "indexed", [2 3], @(x, y) sum (x(:)) == y, 2),
%! logical ([0 1 0 1
%! 0 1 1 0
%! 1 0 1 0
%! 0 0 0 0]));
## Check uint8 and uint16 padding (only the padding since the class of
## the output is dependent on the function and sum() always returns double)
%!assert (nlfilter (uint8 (eye (4)), "indexed", [2 3], @(x) sum (x(:))),
%! [2 2 1 0
%! 1 2 2 1
%! 0 1 2 2
%! 0 0 1 1]);
%!assert (nlfilter (int16 (eye (4)), "indexed", [2 3], @(x) sum (x(:))),
%! [4 2 1 2
%! 3 2 2 3
%! 2 1 2 4
%! 4 3 4 5]);
## Check if function class is preserved
%!assert (nlfilter (uint8 (eye (4)), "indexed", [2 3], @(x) int8 (sum (x(:)))),
%! int8 ([2 2 1 0
%! 1 2 2 1
%! 0 1 2 2
%! 0 0 1 1]));
## Test N-dimensional
%!test
%! a = randi (10, 20, 20, 20);
%! ## extra dimensions on matrix only
%! assert (nlfilter (a, [5 5], @(x) max(x(:))), imdilate (a, ones (5)))
%! ## extra dimensions on both matrix and block
%! assert (nlfilter (a, [5 5 5], @(x) max(x(:))), imdilate (a, ones ([5 5 5])))
%! ## extra dimensions and padding
%! assert (nlfilter (a, [3 7], @(x) max(x(:))), imdilate (a, ones ([3 7])))
%! assert (nlfilter (a, [3 7 3], @(x) max(x(:))), imdilate (a, ones ([3 7 3])))
%!test
%! a = randi (10, 15, 15, 4, 8, 3);
%! assert (nlfilter (a, [3 4 7 5], @(x) max(x(:))),
%! imdilate (a, ones ([3 4 7 5])))
## Just to make sure it's not a bug in imdilate
%!test
%! a = randi (10, 15, 15, 4, 3, 8);
%! ord = ordfiltn (a, 3, ones ([3 7 3 1 5]));
%! assert (nlfilter (a, [3 7 3 1 5], @(x) sort (x(:))(3)), ord)
%! assert (nlfilter (a, [3 7 3 1 5], @(x, y) sort (x(:))(y), 3), ord)
|