This file is indexed.

/usr/share/octave/packages/image-2.6.1/imcrop.m is in octave-image 2.6.1-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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
## Copyright (C) 2014-2015 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} {} imcrop ()
## @deftypefnx {Function File} {} imcrop (@var{img})
## @deftypefnx {Function File} {} imcrop (@var{ind}, @var{cmap})
## @deftypefnx {Function File} {} imcrop (@var{h})
## @deftypefnx {Function File} {} imcrop (@dots{}, @var{rect})
## @deftypefnx {Function File} {[@var{cropped}] =} imcrop (@dots{})
## @deftypefnx {Function File} {[@var{cropped}, @var{rect}] =} imcrop (@dots{})
## @deftypefnx {Function File} {[@var{x}, @var{y}, @var{cropped}, @var{rect}] =} imcrop (@dots{})
## Crop image.
##
## Displays the image @var{img} in a figure window and waits for the user to
## select two points defining a bounding box.  For an indexed image, a
## corresponding colormap can be specified in @var{cmap}.  For multi-dimensional
## images (each 2D image is concatenated in the 4th dimension), only the
## first image is displayed.
##
## If no image data is given, uses the current figure or figure from graphics
## handle @var{h}.
##
## Non-interactive usage is supported if the last input argument is 4 element
## vector @var{rect} defining the region of interest.  The first two elements
## specify the initial @var{x_ini} and @var{y_ini} coordinates, and the last
## two the @var{width} and @var{height}, i.e.,
## @code{@var{rect} = [@var{x_ini} @var{y_ini} @var{width} @var{height}]}.
## Note how this the opposite of the majority of Octave indexing rules where
## rows come before columns.
##
## Returns the @var{cropped} image and a vector @var{rect} with the
## coordinates and size for @var{cropped}.  If more than 3 output arguments
## are requested, also returns the @var{x} and @var{y} data that define
## the coordinate system.
##
## @emph{Note}: the values in @var{rect} are not necessarily integer values
## and can't always be used directly as index values for other images.  To
## crop the same region from a multiple images of the same size, either using
## a multi-dimensional image:
##
## @example
## @group
## nd_img = cat (4, img1, img2, img3, img4);
## cropped = imcrop (nd_img);
## cropped_1 = cropped(:,:,:,1);
## cropped_2 = cropped(:,:,:,2);
## cropped_3 = cropped(:,:,:,3);
## cropped_4 = cropped(:,:,:,4);
## @end group
## @end example
##
## or multiple calls to @code{imcrop}:
##
## @example
## @group
## [cropped_1, rect] = imcrop (img1);
## cropped_2         = imcrop (img2, rect);
## cropped_3         = imcrop (img3, rect);
## cropped_4         = imcrop (img4, rect);
## @end group
## @end example
##
## @seealso{impixel, imshow}
## @end deftypefn

## TODO not yet implemented
## @deftypefnx {Function File} {} imcrop (@var{xData}, @var{yData}, @dots{})

function varargout = imcrop (varargin)

  ## Screw Matlab and their over complicated API's! How can we properly
  ## parse all the possible alternative calls? See
  ## http://www.youtube.com/watch?v=1oZWacjmYm8 to understand how such
  ## API's develop.

  ## There is no check for this things, anything is valid. We (Octave)
  ## are at least checking the number of elements otherwise the input
  ## parsing would be horrible.
  valid_rect   = @(x) numel (x) == 4;
  valid_system = @(x) numel (x) == 2;

  rect = [];
  interactive = true;   # is interactive usage
  alt_system  = false;  # was an alternative coordinate system requested?
  from_fig    = false;  # do we have the image data or need to fetch from figure?

  if (nargin > 5)
    print_usage ();
  endif

  rect = [];
  if (numel (varargin) > 1 && valid_rect (varargin{end}))
    interactive = false;
    rect = varargin{end};
    varargin(end) = [];
  endif

  xdata = [];
  ydata = [];
  if (numel (varargin) > 2 && valid_system (varargin{1}) && valid_system (varargin{2}))
    ## requested messy stuff
    ## we should probably reuse part of what impixel does
    alt_system = true;
    xdata = varargin{1};
    ydata = varargin{2};
    varargin([1 2]) = [];
    error ("imcrop: messing around with coordinate system is not implemented");
  endif

  ## After we remove all that extra stuff, we are left with the image
  fnargin = numel (varargin);
  if (fnargin > 2)
    print_usage ();
  elseif (fnargin == 0)
    ## use current figure
    from_fig = true;
    h = gcf ();
  ## We check isscalar() because ishandle() accepts arrays of handles, and we
  ## check "!= 0" because 0 is and handle for the "root figure" which is
  ## invalid for imcrop (see bug #42714).
  elseif (fnargin == 1 && isscalar (varargin{1})
          && varargin{1} != 0 && ishandle (varargin{1}))
    ## use specified figure
    from_fig = true;
    h = varargin{1};
  elseif (interactive)
    ## leave input check to imshow
    h = nd_imshow (varargin{:});
  elseif (isimage (varargin{1}))
    ## we have the image data and it's not interactive, so there is
    ## nothing to do. We only check the minimum in the image.
  else
    print_usage ();
  endif

  if (from_fig)
    hax = get (h, "currentaxes");
    himage = findobj (hax, "type", "image");
    if (! isempty (himage))
      himage = himage(1);
    else
      error ("imcrop: expect the current axes to contain an image")
    endif
    cdata = get (himage, "cdata");
    xdata = get (himage, "xdata");
    ydata = get (himage, "ydata");
  else
    cdata = varargin{1};
    if (! alt_system)
      xdata = [1 columns(cdata)];
      ydata = [1 rows(cdata)];
    endif
  endif

  ## Finally, crop the image
  if (interactive)
    [x, y] = ginput (2);
    if (x(2) < x(1))
      [x(1), x(2)] = deal (x(2), x(1));
    endif
    if (y(2) < y(1))
      [y(1), y(2)] = deal (y(2), y(1));
    endif
    rect = [x(1) y(1) x(2)-x(1) y(2)-y(1)];
  endif
  i_ini = round ([rect(1) rect(2)]);
  i_end = round ([rect(1)+rect(3) rect(2)+rect(4)]);
  img = cdata(i_ini(2):i_end(2), i_ini(1):i_end(1),:,:); # don't forget RGB and ND images

  ## Even the API for the output is complicated
  if (nargout == 0 && interactive)
    figure ();
    ## In case we have a colormap or something like that, use
    ## it again when displaying the cropped image.
    nd_imshow (img, varargin{2:end});
  elseif (nargout < 3)
    varargout{1} = img;
    varargout{2} = rect;
  else
    varargout{1} = xdata;
    varargout{2} = ydata;
    varargout{3} = img;
    varargout{4} = rect;
  endif

endfunction

## shadows core function to support ND image.  If we have one, use
## the first frame only
function h = nd_imshow (varargin)
  size (varargin{1});
  h = imshow (varargin{1}(:,:,:,1), varargin{2:end});
endfunction

## test typical non-interactive usage, grayscale image
%!test
%! a = randi (255, [100 100]);
%! rect = [20 30 3 5];
%! assert (nthargout ([1 2], @imcrop, a, rect), {a(30:35, 20:23) rect});
%! assert (nthargout (2, @imcrop, a, rect), rect);
%! assert (nthargout ([3 4], 4, @imcrop, a, rect), {a(30:35, 20:23) rect});

## test typical non-interactive usage, RGB image
%!test
%! rgb = randi (255, [100 100 3]);
%! rect = [20 30 3 5];
%! assert (nthargout ([1 2], @imcrop, rgb, rect), {rgb(30:35, 20:23,:) rect});
%! assert (nthargout (2, @imcrop, rgb, rect), rect);
%! assert (nthargout ([3 4], 4, @imcrop, rgb, rect), {rgb(30:35, 20:23,:) rect});

## test typical non-interactive usage, indexed image
%!test
%! a = randi (255, [100 100]);
%! rect = [20 30 3 5];
%! cmap = jet (255);
%! assert (nthargout ([1 2], @imcrop, a, cmap, rect), {a(30:35, 20:23) rect});
%! assert (nthargout (2, @imcrop, a, cmap, rect), rect);
%! assert (nthargout ([3 4], 4, @imcrop, a, cmap, rect), {a(30:35, 20:23) rect});

## test typical non-interactive usage, logical image
%!test
%! a = rand (100) > 0.5;
%! rect = [20 30 3 5];
%! assert (nthargout ([1 2], @imcrop, a, rect), {a(30:35, 20:23) rect});
%! assert (nthargout (2, @imcrop, a, rect), rect);
%! assert (nthargout ([3 4], 4, @imcrop, a, rect), {a(30:35, 20:23) rect});

## 0 is the root figure (always true figure handle), so make sure we use
## scalar 0 as image data, not as figure handle.
%!assert (imcrop (0, [0.5 0.5 0.9 0.9]), 0);
%!assert (imcrop (zeros (5), [1 1 1 1]), zeros (2));