/usr/share/octave/packages/image-2.2.2/colfilt.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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | ## 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} {} colfilt (@var{A}, @var{block_size}, @var{block_type}, @var{func})
## @deftypefnx {Function File} {} colfilt (@var{A}, @var{block_size}, @var{subsize}, @var{block_type}, @var{func}, @dots{})
## @deftypefnx {Function File} {} colfilt (@var{A}, "indexed", @dots{})
## @deftypefnx {Function File} {} colfilt (@dots{}, @var{func}, @var{extra_args}, @dots{})
## Apply function to matrix blocks
##
## Executes the function @var{func} on blocks 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.
##
## The different blocks are organized into a matrix, each block as a
## single column, and passed as the first to the function handle
## @var{func}. Any input arguments to @code{colfilt} after @var{func}
## are passed to @var{func} after the blocks matrix.
##
## Blocks can be of two different types as defined by the string @var{block_type}:
##
## @table @asis
## @item @qcode{"distinct"}
## Each block is completely distinct from the other, with no overlapping
## elements. @var{func} must return a matrix of exactly the same size as
## its input.
##
## @item @qcode{"sliding"}
## Each possible block of size @var{block_size} inside @var{A} is used.
## @var{func} should act along the column dimension (be a column
## compression function) and return a vector of length equal to the
## number of columns of its input.
##
## @end table
##
## The optional argument @var{subsize} divides @var{A} into smaller pieces
## before generating the matrices with one block per column in order to
## save memory. It is currently only accepted for @sc{Matlab} compatibility.
##
## If @var{A} is an indexed image, the second argument should be the
## string @qcode{"indexed"} so that any required padding is done correctly.
## The padding value will be 0 except for indexed images of class uint8
## and uint16.
##
## This function is mostly useful to apply moving or sliding window filter
## when @var{block_type} is "sliding". However, for many cases, specialized
## functions perform much faster. For the following common cases, consider
## the suggested alternatives;
##
## @table @asis
## @item moving average
## A moving average filter is equivalent to convolve with a matrix
## of @code{1/@var{N}} sized @var{block_size}, where @var{N} is the total
## number of elements in a block. Use
## @code{convn (@var{A}, (1/@var{N}) * ones (@var{block_size}) *, "same")}
##
## @item maximum or minimum
## This is the equivalent to a dilation and erosion. Use @code{imdilate} or
## @code{imerode}.
##
## @item any or all
## Same as dilation and erosion but with logical input. Use @code{imdilate}
## or @code{imerode} with @code{logical (@var{A})}.
##
## @item median
## Use @code{medfilt2} if @var{A} is only 2 dimensional, and @code{ordfiltn}
## with the @code{floor (prod (@var{N}/ 2)} th element, where @var{N} is the
## total number of elements in a block (add 1 if it is an even number).
##
## @item sort or nth_element
## Use @code{ordfiltn}.
##
## @item standard deviation
## Use @code{stdfilt}.
##
## @item sum
## Use a matrix of 1 to perform convolution,
## @code{convn (@var{A}, ones (@var{block_size}), "same")}
##
## @end table
##
## @seealso{bestblk, blockproc, col2im, im2col, nlfilter}
## @end deftypefn
function B = colfilt (A, varargin)
## Input check
if (nargin < 4)
print_usage ();
endif
[p, block_size, padval] = im2col_check ("colfilt", nargin, A, varargin{:});
subsize = size (A);
if (numel (varargin) < p)
print_usage ();
elseif (isnumeric (varargin{p}) && isvector (varargin{p}))
subsize = varargin{p++};
subsize = postpad (subsize, ndims (A), 1);
subsize = min (subsize, size (A));
subsize = max (subsize, block_size);
endif
## We need at least 2 more arguments (block type and function)
if (numel (varargin) < p +1)
print_usage ();
endif
## Next one needs to be block type
block_type = varargin{p++};
if (! ischar (block_type))
error ("colfilt: BLOCK_TYPE must be a string");
endif
## followed by the function
func = varargin{p++};
if (! isa (func, "function_handle"))
error ("colfilt: FUNC must be a function handle");
endif
## anything after this are extra arguments to func
extra_args = varargin(p:end);
switch (tolower (block_type))
case "sliding"
## Function must return a single vector, one element per column,
## i.e., should act along the elements of each column.
## TODO for some large blocks, we may easily try to create matrix
## too large for Octave (see im2col documentation about the
## size). May be a good idea to split it into smaller images
## even if subsize is that large, so that we never go above
## sizemax ().
## However, this can be tricky. After splitting the image in
## smaller blocks, they can't be distinct, some parts need
## to overlap otherwise when we put them back together, we'll
## introduce many artifacts.
padded = pad_for_sliding_filter (A, block_size, padval);
cols = im2col (padded, block_size, "sliding");
B = col2im (func (cols, extra_args{:}), block_size, size (padded), "sliding");
case "distinct"
## Function must return a matrix with the same number of elements
## as its input, specially the same number of rows.
## One of the options of this function is to do the block
## processing already from big blocks from the original matrix
## in order to save memory. While this may make sense with
## sliding blocks, not so much here since cols will have the same
## size as A, and so will B.
cols = im2col (A, block_size, "distinct");
B = col2im (func (cols, extra_args{:}), block_size, size (A), "distinct");
otherwise
error ("colfilt: invalid BLOCK_TYPE `%s'.", block_type);
endswitch
endfunction
%!demo
%! ## Perform moving average filter with a 4x4 window
%! A = magic (12)
%! colfilt (A, [4 4], "sliding", @mean)
%!test
%! A = reshape (1:36, [6 6]);
%! assert (colfilt (A, [2 2], [3 3], "sliding", @sum),
%! conv2 (A, ones (2), "same"));
|