This file is indexed.

/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"));