changeset 227:1a4b84759d2c

New functions and an update of imresize to use imremap
author hauberg
date Sat, 13 Jan 2007 14:43:38 +0000
parents 015626391be7
children 5dc5f8566898
files INDEX inst/imperspectivewarp.m inst/imremap.m inst/imresize.m
diffstat 4 files changed, 445 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/INDEX
+++ b/INDEX
@@ -10,7 +10,9 @@
  imginfo
  bmpwrite jpgread jpgwrite pngread pngwrite
 Reshape
- imcrop 
+ imcrop
+ imremap
+ imperspectivewarp 
  imresize 
  imrotate
  imrotate_Fourier
new file mode 100644
--- /dev/null
+++ b/inst/imperspectivewarp.m
@@ -0,0 +1,161 @@
+## Copyright (C) 2006  Søren Hauberg
+## 
+## 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 2, 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 file.  If not, write to the Free Software Foundation,
+## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} @var{warped} = imperspectivewarp(@var{im}, @var{P}, @var{interp}, @var{bbox}, @var{extrapval})
+## @deftypefnx{Function File} [@var{warped}, @var{valid}] = imperspectivewarp(...)
+## Applies the spatial perspective homogeneous transformation @var{P} to the image @var{im}.
+## The transformation matrix @var{P} must be a 3x3 homogeneous matrix, or 2x2 or 2x3
+## affine transformation matrix.
+## 
+## The resulting image @var{warped} is computed using an interpolation method that
+## can be selected through the @var{interp} argument. This must be one
+## of the following strings
+## @table @code
+## @item "nearest"
+## Nearest neighbor interpolation.
+## @item "linear"
+## @itemx "bilinear"
+## Bilinear interpolation. This is the default behavior.
+## @item "cubic"
+## @itemx "bicubic"
+## Bicubic interpolation.
+## @end table
+##
+## By default the resulting image contains the entire warped image. In some situation
+## you only parts of the warped image. The argument @var{bbox} controls this, and can
+## be one of the following strings
+## @table @code
+## @item "loose"
+## The entire warped result is returned. This is the default behavior.
+## @item "crop"
+## The central part of the image of the same size as the input image is returned.
+## @end table
+##
+## All values of the result that fall outside the original image will
+## be set to @var{extrapval}. For images of class @code{double} @var{extrapval}
+## defaults to @code{NA} and for other classes it defaults to 0.
+##
+## The optional output @var{valid} is a matrix of the same size as @var{warped}
+## that contains the value 1 in pixels where @var{warped} contains an interpolated
+## value, and 0 in pixels where @var{warped} contains an extrapolated value.
+## @seealso{imremap, imrotate, imresize, imshear, interp2}
+## @end deftypefn
+
+function [warped, valid] = imperspectivewarp(im, P, interp = "bilinear", bbox = "loose", extrapolation_value = NA)
+  ## Check input
+  if (nargin < 2)
+    print_usage();
+  endif
+  
+  if (!(isgray(im) || isrgb(im)))
+    error("imperspectivewarp: first input argument must be an image");
+  endif
+  
+  if (ismatrix(P) && ndims(P) == 2)
+    if (issquare(P) && rows(P) == 3) # 3x3 matrix
+      if (P(3,3) != 0)
+        P /= P(3,3);
+      else
+        error("imperspectivewarp: P(3,3) must be non-zero");
+      endif
+    elseif (rows(P) == 2 && (columns(P) == 2 || columns(P) == 3)) # 2x2 or 2x3 matrix
+      P(3,3) = 1;
+    else # unsupported matrix size
+      error("imperspectivewarp: transformation matrix must be 2x2, 2x3, or 3x3");
+    endif
+  else
+    error("imperspectivewarp: transformation matrix not valid");
+  endif
+  
+  if (!any(strcmpi(interp, {"nearest", "linear", "bilinear", "cubic", "bicubic", "pchip"})))
+    error("imperspectivewarp: unsupported interpolation method");
+  endif
+  if (any(strcmpi(interp, {"bilinear", "bicubic"})))
+    interp = interp(3:end); # Remove "bi"
+  endif
+  interp = lower(interp);
+  
+  if (!any(strcmpi(bbox, {"loose", "crop"})))
+    error("imperspectivewarp: bounding box must be either 'loose' or 'crop'");
+  endif
+  
+  if (!isscalar(extrapolation_value))
+    error("imperspective: extrapolation value must be a scalar");
+  endif
+  
+  ## Do the transformation
+  [y, x, tmp] = size(im);
+  ## Transform corners
+  corners = [1, 1, 1;
+             1, y, 1;
+             x, 1, 1;
+             x, y, 1]';
+  Tcorners = P*corners;
+  Tx = Tcorners(1,:)./Tcorners(3,:);
+  Ty = Tcorners(2,:)./Tcorners(3,:);
+
+  ## Do cropping?
+  x1 = round(min(Tx)); x2 = round(max(Tx));
+  y1 = round(min(Ty)); y2 = round(max(Ty));
+  # FIXME: This seems to work fine for rotations, but
+  # somebody who knows computational geometry should
+  # be able to come up with a better algorithm.
+  if (strcmpi(bbox, "crop"))
+    xl = x2 - x1 + 1;
+    yl = y2 - y1 + 1;
+    xd = (xl - x)/2;
+    yd = (yl - y)/2;
+    x1 += xd; x2 -= xd;
+    y1 += yd; y2 -= yd;
+  endif
+ 
+  ## Transform coordinates
+  [X, Y] = meshgrid(x1:x2, y1:y2);
+  [sy, sx] = size(X);
+  D = [X(:), Y(:), ones(sx*sy, 1)]';
+  PD = inv(P)*D;
+  XI = PD(1,:)./PD(3,:);
+  YI = PD(2,:)./PD(3,:);
+  XI = reshape(XI, sy, sx);
+  YI = reshape(YI, sy, sx);
+  
+  ## Interpolate
+  [warped, valid] = imremap(im, XI, YI, interp, extrapolation_value);
+
+endfunction
+
+%!demo
+%! ## Generate a synthetic image and show it
+%! I = tril(ones(100)) + abs(rand(100)); I(I>1) = 1;
+%! I(20:30, 20:30) = !I(20:30, 20:30);
+%! I(70:80, 70:80) = !I(70:80, 70:80);
+%! imshow(I);
+%! ## Resize the image to the double size and show it
+%! P = diag([1, 1, 0.5]);
+%! warped = imperspectivewarp(I, P);
+%! imshow(warped);
+
+%!demo
+%! ## Generate a synthetic image and show it
+%! I = tril(ones(100)) + abs(rand(100)); I(I>1) = 1;
+%! I(20:30, 20:30) = !I(20:30, 20:30);
+%! I(70:80, 70:80) = !I(70:80, 70:80);
+%! imshow(I);
+%! ## Rotate the image around (0, 0) by -0.4 radians and show it
+%! R = [cos(-0.4) sin(-0.4); -sin(-0.4) cos(-0.4)];
+%! warped = imperspectivewarp(I, R);
+%! imshow(warped);
new file mode 100644
--- /dev/null
+++ b/inst/imremap.m
@@ -0,0 +1,223 @@
+## Copyright (C) 2006  Søren Hauberg
+## 
+## 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 2, 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 file.  If not, write to the Free Software Foundation,
+## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} @var{warped} = imremap(@var{im}, @var{XI}, @var{YI})
+## @deftypefnx{Function File} @var{warped} = imremap(@var{im}, @var{XI}, @var{YI}, @var{interp}, @var{extrapval})
+## @deftypefnx{Function File} [@var{warped}, @var{valid} ] = imremap(...)
+## Applies any geometric transformation to the image @var{im}.
+##
+## The arguments @var{XI} and @var{YI} are lookup tables that define the resulting
+## image
+## @example
+## @var{warped}(y,x) = @var{im}(@var{YI}(y,x), @var{XI}(y,x))
+## @end example
+## where @var{im} is assumed to be a continuous function, which is achieved
+## by interpolation. Note that the image @var{im} is expressed in a (X, Y)-coordinate
+## system and not a (row, column) system.
+##
+## The argument @var{interp} selects the used interpolation method, and most be one
+## of the following strings
+## @table @code
+## @item "nearest"
+## Nearest neighbor interpolation.
+## @item "linear"
+## @itemx "bilinear"
+## Bilinear interpolation. This is the default behavior.
+## @item "cubic"
+## @itemx "bicubic"
+## Bicubic interpolation.
+## @end table
+##
+## All values of the result that fall outside the original image will
+## be set to @var{extrapval}. For images of class @code{double} @var{extrapval}
+## defaults to @code{NA} and for other classes it defaults to 0.
+##
+## The optional output @var{valid} is a matrix of the same size as @var{warped}
+## that contains the value 1 in pixels where @var{warped} contains an interpolated
+## value, and 0 in pixels where @var{warped} contains an extrapolated value.
+## @seealso{imperspectivewarp, imrotate, imresize, imshear, interp2}
+## @end deftypefn
+
+function [warped, valid] = imremap(im, XI, YI, interp = "bilinear", extrapval = NA)
+  ## Check input
+  if (nargin < 3)
+    print_usage();
+  endif
+  
+  if (!(isgray(im) || isrgb(im)))
+    error("imremap: first input argument must be an image");
+  endif
+  
+  if (!size_equal(XI, YI) || !ismatrix(XI) || ndims(XI) != 2)
+    error("imremap: XI and YI must be matrices of the same size");
+  endif
+  
+  if (!any(strcmpi(interp, {"nearest", "linear", "bilinear", "cubic", "bicubic"})))
+    error("imremap: unsupported interpolation method");
+  endif
+  if (any(strcmpi(interp, {"bilinear", "bicubic"})))
+    interp = interp(3:end); # Remove "bi"
+  endif
+  interp = lower(interp);
+  
+  if (!isscalar(extrapval))
+    error("imremap: extrapolation value must be a scalar");
+  endif
+  
+  ## Interpolate
+  if (isgray(im))
+    warped = grayinterp(im, XI, YI, interp, NA);
+  else # rgb image
+    for i = 3:-1:1
+      warped(:,:,i) = grayinterp(im(:,:,i), XI, YI, interp, NA);
+    endfor
+  endif
+  valid = !isna(warped);
+  warped(!valid) = extrapval;
+
+  ## Change the class of the results according to the class of the image
+  c = class(im);
+  if (strcmpi(c, "uint8"))
+    warped = uint8(warped);
+  elseif (strcmpi(c, "uint16"))
+    warped = uint16(warped);
+  endif
+
+endfunction
+
+function [warped, valid] = grayinterp(im, XI, YI, interp, extrapval)
+  if (strcmp(interp, "cubic"))
+    warped = graybicubic(double(im), XI, YI, NA);
+  else
+    warped = interp2(double(im), XI, YI, interp, NA);
+  endif
+  valid = !isna(warped);
+  warped(!valid) = extrapval;
+endfunction
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{zi}=} bicubic (@var{x}, @var{y}, @var{z}, @var{xi}, @var{yi})
+## Reference:
+## Image Processing, Analysis, and Machine Vision, 2nd Ed.
+## Sonka et.al.
+## Brooks/Cole Publishing Company
+## ISBN: 0-534-95393-X
+## @seealso{interp2}
+## @end deftypefn
+
+function ZI = graybicubic (Z, XI, YI, extrapval = NA)
+  
+  ## Allocate output
+  [X, Y] = meshgrid(1:columns(Z), 1:rows(Z));
+  [Zr, Zc] = size(XI);
+  ZI = zeros(Zr, Zc);
+  
+  ## Find inliers
+  inside = !( XI < X(1) | XI > X(end) | YI < Y(1) | YI > Y(end) );
+  
+  ## Scale XI and YI to match indices of Z (not needed when interpolating images)
+  #XI = (columns(Z)-1) * ( XI - X(1) ) / (X(end)-X(1)) + 1;
+  #YI = (rows(Z)-1)    * ( YI - Y(1) ) / (Y(end)-Y(1)) + 1;
+  
+  ## Start the real work
+  K = floor(XI);
+  L = floor(YI);
+
+  ## Coefficients
+  AY1  = bc((YI-L+1)); AX1  = bc((XI-K+1));
+  AY0  = bc((YI-L+0)); AX0  = bc((XI-K+0));
+  AY_1 = bc((YI-L-1)); AX_1 = bc((XI-K-1));
+  AY_2 = bc((YI-L-2)); AX_2 = bc((XI-K-2));
+
+  ## Perform interpolation
+  sz = size(Z);
+  %ZI(inside) = AY_2 .* AX_2 .* Z(sym_sub2ind(sz, L+2, K+2)) ...
+  ZI = AY_2 .* AX_2 .* Z(sym_sub2ind(sz, L+2, K+2)) ...
+     + AY_2 .* AX_1 .* Z(sym_sub2ind(sz, L+2, K+1))    ...
+     + AY_2 .* AX0  .* Z(sym_sub2ind(sz, L+2, K)) ...
+     + AY_2 .* AX1  .* Z(sym_sub2ind(sz, L+2, K-1)) ...
+     + AY_1 .* AX_2 .* Z(sym_sub2ind(sz, L+1, K+2)) ...
+     + AY_1 .* AX_1 .* Z(sym_sub2ind(sz, L+1, K+1))    ...
+     + AY_1 .* AX0  .* Z(sym_sub2ind(sz, L+1, K)) ...
+     + AY_1 .* AX1  .* Z(sym_sub2ind(sz, L+1, K-1)) ...
+     + AY0  .* AX_2 .* Z(sym_sub2ind(sz, L,   K+2)) ...
+     + AY0  .* AX_1 .* Z(sym_sub2ind(sz, L,   K+1))    ...
+     + AY0  .* AX0  .* Z(sym_sub2ind(sz, L,   K)) ...
+     + AY0  .* AX1  .* Z(sym_sub2ind(sz, L,   K-1)) ...
+     + AY1  .* AX_2 .* Z(sym_sub2ind(sz, L-1, K+2)) ...
+     + AY1  .* AX_1 .* Z(sym_sub2ind(sz, L-1, K+1))    ...
+     + AY1  .* AX0  .* Z(sym_sub2ind(sz, L-1, K)) ...
+     + AY1  .* AX1  .* Z(sym_sub2ind(sz, L-1, K-1));
+  ZI(!inside) = extrapval;
+
+endfunction
+
+## Checks if data is meshgrided
+function b = isgriddata(X)
+  D = X - repmat(X(1,:), rows(X), 1);
+  b = all(D(:) == 0);
+endfunction
+
+## Checks if data is equally spaced (assumes data is meshgrided)
+function b = isequallyspaced(X)
+  Dx = gradient(X(1,:));
+  b = all(Dx == Dx(1));
+endfunction
+
+## Computes the interpolation coefficients
+function o = bc(x)
+  x = abs(x);
+  o = zeros(size(x));
+  idx1 = (x < 1);
+  idx2 = !idx1 & (x < 2);
+  o(idx1) = 1 - 2.*x(idx1).^2 + x(idx1).^3;
+  o(idx2) = 4 - 8.*x(idx2) + 5.*x(idx2).^2 - x(idx2).^3;
+endfunction
+
+## This version of sub2ind behaves as if the data was symmetrically padded
+function ind = sym_sub2ind(sz, Y, X)
+  Y(Y<1) = 1 - Y(Y<1);
+  Y(Y>sz(1)) = 2*sz(1) - Y(Y>sz(1));
+  X(X<1) = 1 - X(X<1);
+  X(X>sz(2)) = 2*sz(2) - X(X>sz(2));
+  ind = sub2ind(sz, Y, X);
+endfunction
+
+%!demo
+%! ## Generate a synthetic image and show it
+%! I = tril(ones(100)) + abs(rand(100)); I(I>1) = 1;
+%! I(20:30, 20:30) = !I(20:30, 20:30);
+%! I(70:80, 70:80) = !I(70:80, 70:80);
+%! imshow(I);
+%! ## Resize the image to the double size and show it
+%! [XI, YI] = meshgrid(linspace(1, 100, 200));
+%! warped = imremap(I, XI, YI);
+%! imshow(warped);
+
+%!demo
+%! ## Generate a synthetic image and show it
+%! I = tril(ones(100)) + abs(rand(100)); I(I>1) = 1;
+%! I(20:30, 20:30) = !I(20:30, 20:30);
+%! I(70:80, 70:80) = !I(70:80, 70:80);
+%! imshow(I);
+%! ## Rotate the image around (0, 0) by -0.4 radians and show it
+%! [XI, YI] = meshgrid(1:100);
+%! R = [cos(-0.4) sin(-0.4); -sin(-0.4) cos(-0.4)];
+%! RXY = [XI(:), YI(:)] * R;
+%! XI = reshape(RXY(:,1), [100, 100]); YI = reshape(RXY(:,2), [100, 100]);
+%! warped = imremap(I, XI, YI);
+%! imshow(warped);
--- a/inst/imresize.m
+++ b/inst/imresize.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2005 Søren Hauberg
+## Copyright (C) 2005 Søren Hauberg
 ## 
 ## 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
@@ -15,47 +15,47 @@
 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
 ## -*- texinfo -*-
-## @deftypefn  {Function File} @var{B}= imresize (@var{A}, @var{m})
-## @deftypefnx {Function File} @var{B}= imresize (@var{A}, @var{m}, @var{method})
+## @deftypefn {Function File} @var{B}= imresize (@var{A}, @var{m})
+## Scales the image @var{A} by a factor @var{m} using nearest neighbour
+## interpolation. If @var{m} is less than 1 the image size will be reduced,
+## and if @var{m} is greater than 1 the image will be enlarged. If the image
+## is being enlarged the it will be convolved with a 11x11 Gaussian FIR filter
+## to reduce aliasing. See below on how to alter this behavior.
+##
+## @deftypefnx {Function File} @var{B}= imresize (@var{A}, @var{m}, @var{interp})
+## Same as above except @var{interp} interpolation is performed instead of
+## using nearest neighbour. @var{interp} can be any interpolation method supported by interp2.
+##
 ## @deftypefnx {Function File} @var{B}= imresize (@var{A}, [@var{mrow} @var{mcol}])
-## @deftypefnx {Function File} @var{B}= imresize (@var{A}, [@var{mrow} @var{mcol}], @var{method})
-## @deftypefnx {Function File} @var{B}= imresize (..., @var{method}, @var{fsize})
-## @deftypefnx {Function File} @var{B}= imresize (..., @var{method}, @var{filter})
-## Resizes the image @var{A} to a given size using any interpolation
-## method supported by @code{interp2}.
-##
-## If the second argument is a scalar @var{m} the image will be scaled
-## by a factor @var{m}. If the second argument is a two-vector 
-## [@var{mrow}, @var{mcol}] the resulting image will be resized to have
-## this size.
+## Scales the image @var{A} to be of size @var{mrow}x@var{mcol} using nearest
+## neighbour interpolation. If the image is being enlarged it will be convolved
+## with a lowpass FIR filter as described above.
 ##
-## The third argument controls the kind of interpolation used to perform
-## the resizing. This can be any method supported by @code{interp2}, and
-## defaults to nearest neighbour interpolation.
+## @deftypefnx {Function File} @var{B}= imresize (@var{A}, [@var{mrow} @var{mcol}], @var{interp})
+## Same as above except @var{interp} interpolation is performed instead of using
+## nearest neighbour. @var{interp} can be any interpolation method supported by interp2.
 ##
-## The fourth argument controls if the image is filtered before resizing
-## to prevent aliasing. If the fourth argument is a two-vector 
-## [@code{frow}, @code{fcol}], the image will be convolved with a
-## @code{frow}x@code{fcol} gaussian filter. If it is a matrix it will
-## be used as a filter. The default is not to filter the image if it
-## is reduced in size, and to filter it by an 11x11 gaussian filter if
-## the image is enlarged. Setting the filter to 0 will turn of any
-## filtering.
-## @seealso{interp2}
+## @deftypefnx {Function File} @var{B}= imresize (..., @var{interp}, @var{fsize})
+## If the image the image is being reduced it will usually be convolved with
+## a 11x11 Gaussian FIR filter. By setting @var{fsize} to 0 this will be turned
+## off, and if @var{fsize} > 0 the image will be convolved with a @var{fsize}
+## by @var{fsize} Gaussian FIR filter.
+##
+## @deftypefnx {Function File} @var{B}= imresize (..., @var{interp}, @var{filter})
+## If the image size is being reduced and the @var{filter} argument is passed to
+## imresize the image will be convolved with @var{filter} before the resizing
+## takes place.
+##
+## @seealso{imremap, imrotate, interp2}
 ## @end deftypefn
 
-## Author: Søren Hauberg <hauberg at gmail dot com>
-## 
-## 2005-04-14 Søren Hauberg <hauberg at gmail dot com>
-## * Initial revision
+function ret = imresize(im, m, interp = "nearest", filter = 11)
+  if (!isgray(im) && !isrgb(im))
+    error("imresize: the first argument has must be an image");
+  endif
+  [row, col, num_planes] = size(im);
 
-function [ ret ] = imresize (im, m, method, filter)
-  if (!isgray(im))
-    error("The first argument has to be a gray-scale image.");
-  endif
-  [row col] = size(im);
-
-  # Handle the argument that describes the size of the result
+  ## Handle the argument that describes the size of the result
   if (length(m) == 1)
     new_row = round(row*m);
     new_col = round(col*m);
@@ -64,36 +64,37 @@
     new_col = m(2);
     m = min( new_row/row, new_col/col );
   else
-    error("Bad second argument");
+    error("imresize: second argument mest be a scalar or a 2-vector");
   end
 
-  # Handle the method argument
-  if (nargin < 3)
-    method = "nearest";
+  ## Handle the method argument
+  if (!any(strcmpi(interp, {"nearest", "linear", "bilinear", "cubic", "bicubic", "pchip"})))
+    error("imresize: unsupported interpolation method");
   endif
 
-  # Handle the filterargument
-  if (!strcmp(method, "nearest"))
-    if (nargin < 4)
-      filter = 11;
-    endif
-    if (m > 1 & filter > 0)
-      # If the image is being enlarged and filter > 0 then
-      # convolve the image with a filter*filter gaussian.
-      mu = round(filter/2);
+  ## Handle the filter argument
+  if (!strcmp(interp, "nearest") && m < 1)
+    if (isscalar(filter) && filter > 0)
+      ## If the image is being reduced and filter > 0 then
+      ## convolve the image with a filter*filter gaussian.
+      mu = (filter/2);
       sigma = mu/3;
       x = 1:filter;
       gauss = 1/sqrt(2*pi*sigma^2) * exp( (-(x-mu).^2)/(2*sigma^2) );
-      im = conv2(gauss, gauss, im, "same");
-    elseif (m < 1 & nargin == 4)
-      # If the image size is being reduced and a fourth argument
-      # is given, use it as a FIR filter.
-      im = conv2(im, filter, "same");
+      for i = 1:num_planes
+          im(:,:,i) = conv2(gauss, gauss, im(:,:,i), "same");
+      endfor
+    elseif (nargin >= 4 && ismatrix(filter) && ndims(filter) == 2)
+      ## If the image size is being reduced and a fourth argument
+      ## is given, use it as a FIR filter.
+      for i = 1:num_planes
+        im(:,:,i) = conv2(im(:,:,i), filter, "same");
+      endfor
     endif
   endif
   
-  # Perform the actual resizing
-  [XI YI] = meshgrid( linspace(1,col,new_col), linspace(1,row,new_row) );
-  ret = interp2(im, XI, YI, method);
+  ## Perform the actual resizing
+  [XI, YI] = meshgrid( linspace(1,col,new_col), linspace(1,row,new_row) );
+  ret = imremap(im, XI, YI, interp);
 
 endfunction