This file is indexed.

/usr/share/octave/packages/image-2.2.2/impixel.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
181
182
183
184
185
186
187
188
## 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} {} impixel ()
## @deftypefnx {Function File} {} impixel (@var{img}, @var{x}, @var{y})
## @deftypefnx {Function File} {} impixel (@var{ind}, @var{map}, @var{x}, @var{y})
## @deftypefnx {Function File} {} impixel (@var{xdata}, @var{ydata}, @var{img}, @var{x}, @var{y})
## @deftypefnx {Function File} {} impixel (@var{xdata}, @var{ydata}, @var{ind}, @var{map}, @var{x}, @var{y})
## @deftypefnx {Function File} {[@var{x}, @var{y}, @var{p}] =} impixel (@dots{})
## Get pixel values.
##
## For any image @var{img}, or indexed image @var{ind} with colormap @var{map},
## returns the pixel values at the image coordinates @var{x} and @var{y}.
##
## The 2 element vectors @var{xdata} and @var{ydata} can be used to set an
## alternative coordinate system.
##
## If more than one output argument is requested, also returns the @var{x} and
## @var{y} coordinates for the image.
##
## @itemize @bullet
## @item
## The pixel values are always returned in RGB style triples, even when
## @var{img} is a grayscale image.
##
## @item
## The value for pixel coordinates outside the image limits is NaN.
##
## @item
## Because a floating-point is required to represent a NaN, the pixel
## values will be of class double if input is double, and single otherwise.
## @end itemize
##
## @end deftypefn

function varargout = impixel (varargin)

  if (nargin > 6)
    print_usage ();

  ## interactive usage
  elseif (nargin <= 2)
    ## FIXME not yet implemented
    print_usage ();
    if (nargin == 0)
      ## If using the current image, it is possible that xData and yData
      ## were changed? We will confirm later is they were tampered with.
      xData = get (gcf (), "xData");
      yData = get (gcf (), "yData");
    else
      ## with given image, otherwise we will use current image
      [img, map, is_indexed] = get_image (varargin{:});
    endif

    ## If only 2 output arguments are requested in interactive mode, then
    ## only the coordinates are required, no need to do anything else.
    if (nargout <= 2)
      varargout(1:2) = {x y};
      return
    endif

  ## non-interactive usage
  else
    x = varargin{end-1};
    y = varargin{end};
    if (! isnumeric (x) || ! isreal (x) || ! isnumeric (y) || ! isreal (y))
      error ("impixel: X and Y must be real numbers");
    endif
    x = x(:);
    y = y(:);

    if (nargin >= 5)
      [img, map, is_indexed] = get_image (varargin{3:end-2});
      xData = varargin{1};
      yData = varargin{2};
      if (! isnumeric (xData) || ! isnumeric (yData))
        ## For Matlab compatibility we do not check if there's
        ## only 2 elements, or if they are real numbers
        error ("impixel: XDATA and YDATA must be numeric");
      endif
    else
      [img, map, is_indexed] = get_image (varargin{1:end-2});
      xData = 1:columns (img);
      yData = 1:rows (img);
    endif

  endif

  ## We need to return NaN if the requested pixels are outside the image
  ## limits. interp2() will respect the input class, which means it will
  ## return a 0 instead of NaN if the image is an integer class. Because
  ## of that, we convert it to single. If the input image was double, then
  ## we let it be.
  if (isinteger (img))
    img = single (img);
    if (is_indexed)
      ## There's an offset in indexed images depending on their class. An
      ## indexed image from integer class, matches the value 0 to row 1 of the
      ## colormap. An indexed image from a float class, matches value 1 to
      ## row 1. Since we are changing the class, we need to readjust it.
      img++;
    endif
  endif

  xx   = linspace (min (xData), max (xData), columns (img));
  yy   = linspace (min (yData), max (yData), rows (img));
  data = interp2 (xx, yy, img(:,:,1), x, y, "nearest");
  if (ndims (img) == 3 && size (img, 3) == 3)
    ## We can't use interp3() because XI and YI will be used to select entire
    ## columns and vectors instead of matched coordinates
    for ch = 2:3
      data(:,ch) = interp2 (xx, yy, img(:,:,ch), x, y, "nearest");
    endfor
  endif

  if (is_indexed)
    bad       = isnan (data);
    data(bad) = 1;
    data      = map(data(:),:);
    data([bad bad bad]) = NA;
  elseif (isvector (data))
    ## If we have a vector but the image was not indexed, it must have
    ## been a grayscale image. We need to repeat the values into a Nx3
    ## matrix as if they were RGB values.
    data = [data(:) data(:) data(:)];
  endif

  if (nargout > 1)
    varargout(1:3) = {x y data}
  else
    varargout(1)   = {data};
  endif

endfunction

function [img, map, is_indexed] = get_image (img, map = [])

  if (! isimage (img))
    error ("impixel: invalid image");
  endif

  is_indexed = false;
  if (nargin > 2)
    error ("impixel: too many input arguments");
  elseif (nargin == 2)
    is_indexed = true;
    if (! iscolormap (map))
      error ("impixel: invalid colormap");
    elseif (! isind (img))
      error ("impixel: invalid indexed image");
    endif
  endif

endfunction

%!shared img2d, img3d
%! img2d = uint8 (magic (10));
%! img3d(:,:,1) = img2d;
%! img3d(:,:,2) = img2d + 1;
%! img3d(:,:,3) = img2d + 2;
%! img3d = uint8 (img3d);
%!
%!assert (impixel (img2d, 2, 2), single ([80 80 80]));
%!assert (impixel (img2d, -2, 2), single ([NA NA NA]));
%!
%!assert (impixel (img2d, [1 10], [1 10]), single ([92 92 92; 59 59 59]));
%!assert (impixel (img3d, [1 10], [1 10]), single ([92 93 94; 59 60 61]));
%!assert (impixel (double (img2d), [1 10], [1 10]), [92 92 92; 59 59 59]);
%!
%!assert (impixel ([1 10], [1 10], img2d, [1 10], [1 10]), single ([92 92 92; 59 59 59]));
%!assert (impixel ([3 12], [-4 12], img2d, [1 10], [1 10]), single ([NA NA NA; 44 44 44]));
%!assert (impixel ([3 5], [-4 3], img2d, [1 10], [1 10]), single ([NA NA NA; NA NA NA]));
%!
%! ## the following returns double because it's an indexed image
%!assert (impixel ([3 12], [-4 12], img2d, gray (100), [1 10], [1 10]), [NA NA NA; 4/9 4/9 4/9]);