Mercurial > forge
changeset 11376:1c186f4255de octave-forge
imperspectivewarp, imrotate, imresize, imremap changes.
* do not parse interpolation method. Leave it to interp2
* create private function that lowers case and deals with converting
matlab compatible names to interp2 compatible methods. This extends
this functions to the methods spline, pchip and triangle.
* changes on input checking using isimage, isrgb, isgray and print_usage
* use cast() or eval ("im2" in_class) to return image of same class
as input
author | carandraug |
---|---|
date | Sat, 12 Jan 2013 15:50:13 +0000 |
parents | fde3acd5937a |
children | fff993191048 |
files | main/image/NEWS main/image/inst/imperspectivewarp.m main/image/inst/imremap.m main/image/inst/imresize.m main/image/inst/imrotate.m main/image/inst/private/interp_method.m |
diffstat | 6 files changed, 117 insertions(+), 145 deletions(-) [+] |
line wrap: on
line diff
--- a/main/image/NEWS Sat Jan 12 14:55:51 2013 +0000 +++ b/main/image/NEWS Sat Jan 12 15:50:13 2013 +0000 @@ -52,12 +52,13 @@ ** The performance of `imresize()' has been greatly improved when using the nearest neighbor method for N or 1/N scale factors (e.g.: 2, 50, 1/4, 1/7). - ** The `imresize' function will now accept any interpolation method from - `interp2()' thus extending the available methods to `spline' and `pchip'. - The `triangle' method has also been added (same as the `linear' method). - - ** The `imremap' function will now accept any interpolation method from - `interp2()' thus extending the available methods to `pchip'. + ** The imperspectivewarp, imremap, imresize, and imrotate functions will now + accept any interpolation method from the interp2 function thus extending + the available methods to "spline" and "pchip". This in addition to the + "bilinear" and "bicubic" methods (same as "linear" and "cubic" respectively) + which are kept for matlab compatibility. For the same reason, the + "triangle" method (interpolation kernel) has also been added (which is the + same as "linear" method). Summary of important user-visible changes for image 2.0.0: -------------------------------------------------------------------
--- a/main/image/inst/imperspectivewarp.m Sat Jan 12 14:55:51 2013 +0000 +++ b/main/image/inst/imperspectivewarp.m Sat Jan 12 15:50:13 2013 +0000 @@ -20,19 +20,13 @@ ## 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 +## The optional argument @var{method} defines the interpolation method to be +## used. All methods supported by @code{interp2} can be used. By default, the +## @code{linear} method is used. +## +## For @sc{matlab} compatibility, the methods @code{bicubic} (same as +## @code{cubic}), @code{bilinear} and @code{triangle} (both the same as +## @code{linear}) are also supported. ## ## 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 @@ -56,47 +50,35 @@ ## @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(); +function [warped, valid] = imperspectivewarp(im, P, interp = "linear", bbox = "loose", extrapolation_value = NA) + + if (nargin < 2 || nargin > 5) + print_usage (); + elseif (! isimage (im) || (! isrgb (im) && ! isgray (im))) + error ("imperspectivewarp: IM must be a grayscale or RGB image.") + elseif (! ischar (interp)) + error ("imperspectivewarp: INTERP must be a string with interpolation method") + elseif (! ischar (bbox) || ! any (strcmpi (bbox, {"loose", "crop", "same"}))) + error ("imperspectivewarp: BBOX must be 'loose', 'crop' or 'same'"); + elseif (! isscalar (extrapolation_value)) + error ("imperspectivewarp: EXTRAPVAL must be a scalar"); endif - - [imrows, imcols, imchannels, tmp] = size(im); - if (tmp != 1 || (imchannels != 1 && imchannels != 3)) - error("imperspectivewarp: first input argument must be an image"); - endif + interp = interp_method (interp); 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"); + 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"); + 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"}))) - 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", "same"}))) - error("imperspectivewarp: bounding box must be either 'loose', 'crop', or 'same'"); - endif - - if (!isscalar(extrapolation_value)) - error("imperspective: extrapolation value must be a scalar"); + error ("imperspectivewarp: transformation matrix not valid"); endif ## Do the transformation @@ -140,8 +122,7 @@ clear X Y D PD; - ## Interpolate - [warped, valid] = imremap(im, XI, YI, interp, extrapolation_value); + [warped, valid] = imremap (im, XI, YI, interp, extrapolation_value); endfunction
--- a/main/image/inst/imremap.m Sat Jan 12 14:55:51 2013 +0000 +++ b/main/image/inst/imremap.m Sat Jan 12 15:50:13 2013 +0000 @@ -28,11 +28,14 @@ ## by interpolation. Note that the image @var{im} is expressed in a (X, Y)-coordinate ## system and not a (row, column) system. ## -## The optional argument @var{interp} defines the interpolation method to be -## used. All methods supported by @code{interp2} can be used. In -## addition, the methods @code{bicubic} (same as @code{cubic}), and -## @code{bilinear} (same as @code{linear}) are supported for @sc{matlab} -## compatibility. By default, the @code{linear} method is used. +## The optional argument @var{method} defines the interpolation method to be +## used. All methods supported by @code{interp2} can be used. By default, the +## @code{linear} method is used. +## +## For @sc{matlab} compatibility, the methods @code{bicubic} (same as +## @code{cubic}), @code{bilinear} and @code{triangle} (both the same as +## @code{linear}) are also supported. + ## ## 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} @@ -45,35 +48,22 @@ ## @end deftypefn function [warped, valid] = imremap(im, XI, YI, interp = "linear", extrapval = NA) - ## Check input - if (nargin < 3) - print_usage(); - endif - - [imrows, imcols, imchannels, tmp] = size(im); - if (tmp != 1 || (imchannels != 1 && imchannels != 3)) - 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"); + + if (nargin < 3 || nargin > 5) + print_usage (); + elseif (! isimage (im) || (! isrgb (im) && ! isgray (im))) + error ("imremap: IM must be a grayscale or RGB image.") + elseif (! size_equal (XI, YI) || ! ismatrix (XI) || ndims (XI) != 2) + error ("imremap: XI and YI must be matrices of the same size"); + elseif (! ischar (interp)) + error ("imremap: INTERP must be a string with interpolation method") + elseif (! isscalar (extrapval)) + error ("imremap: EXTRAPVAL must be a scalar"); endif - - ## Handle the interp argument. We do not check for the actual value. We leave - ## that to interp2 so we don't have to keep updating this when interp2 - ## gets new methods - interp = tolower (interp); - switch interp - case "bicubic", interp = "cubic"; - case "bilinear", interp = "linear"; - endswitch - - if (!isscalar(extrapval)) - error("imremap: extrapolation value must be a scalar"); - endif + interp = interp_method (interp); ## Interpolate - if (imchannels == 1) # Gray + if (size (im, 3) == 1) # Gray warped = grayinterp(im, XI, YI, interp, NA); else # rgb image for i = 3:-1:1 @@ -83,13 +73,8 @@ 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 + ## we return image on same class as input + warped = cast (warped, class (im)); endfunction
--- a/main/image/inst/imresize.m Sat Jan 12 14:55:51 2013 +0000 +++ b/main/image/inst/imresize.m Sat Jan 12 15:50:13 2013 +0000 @@ -34,10 +34,12 @@ ## @end example ## ## The optional argument @var{method} defines the interpolation method to be -## used. All methods supported by @code{interp2} can be used. In -## addition, the methods @code{bicubic} (same as @code{cubic}), @code{bilinear} -## and @code{triangle} (both, the same as @code{linear}) are supported for -## @sc{matlab} compatibility. By default, the @code{cubic} method is used. +## used. All methods supported by @code{interp2} can be used. By default, the +## @code{cubic} method is used. +## +## For @sc{matlab} compatibility, the methods @code{bicubic} (same as +## @code{cubic}), @code{bilinear} and @code{triangle} (both the same as +## @code{linear}) are also supported. ## ## @table @asis ## @item bicubic (default) @@ -54,15 +56,17 @@ ## @end deftypefn function im = imresize (im, scale, method = "cubic") + if (nargin < 2 || nargin > 3) - print_usage + print_usage (); elseif (! isimage (im) || (! isrgb (im) && ! isgray (im))) - error ("imerode: IM must be a grayscale or RGB image.") + error ("imresize: IM must be a grayscale or RGB image.") elseif (! isnumeric (scale) || any (scale <= 0)) - error ("imerode: SCALE or [M N] must be numeric positive values") + error ("imresize: SCALE or [M N] must be numeric positive values") elseif (! ischar (method)) - error ("imerode: METHOD must be a string with interpolation method") + error ("imresize: METHOD must be a string with interpolation method") endif + method = interp_method (method); inRows = rows (im); inCols = columns (im); @@ -92,16 +96,6 @@ error ("imresize: SCALE argument must be a scalar or a 2 element vector"); end - ## Handle the method argument. We do not check for the actual value. We leave - ## that to interp2 so we don't have to keep updating this when interp2 - ## gets new methods - method = tolower (method); - switch method - case "bicubic", method = "cubic"; - case "bilinear", method = "linear"; - case "triangle", method = "linear"; - endswitch - ## Perform the actual resizing if (inRows == outRows && inCols == outCols) ## no resizing to do
--- a/main/image/inst/imrotate.m Sat Jan 12 14:55:51 2013 +0000 +++ b/main/image/inst/imrotate.m Sat Jan 12 15:50:13 2013 +0000 @@ -24,20 +24,15 @@ ## ## @var{theta} the rotation angle in degrees counterclockwise ## -## @var{method} -## @itemize @w -## @item "nearest" neighbor: fast, but produces aliasing effects (default). -## @item "bilinear" interpolation: does anti-aliasing, but is slightly slower. -## @item "bicubic" interpolation: does anti-aliasing, preserves edges better -## than bilinear interpolation, but gray levels may slightly overshoot at sharp -## edges. This is probably the best method for most purposes, but also the slowest. -## @item "Fourier" uses Fourier interpolation, decomposing the rotation -## matrix into 3 shears. This method often results in different artifacts than -## homography-based methods. Instead of slightly blurry edges, this method can -## result in ringing artifacts (little waves near high-contrast edges). However, -## Fourier interpolation is better at maintaining the image information, so that -## unrotating will result in an image closer to the original than the other methods. -## @end itemize +## The optional argument @var{method} defines the interpolation method to be +## used. All methods supported by @code{interp2} can be used. In addition, +## Fourier interpolation by decomposing the rotation matrix into 3 shears can +## be used with the @code{fourier} method. By default, the @code{nearest} method +## is used. +## +## For @sc{matlab} compatibility, the methods @code{bicubic} (same as +## @code{cubic}), @code{bilinear} and @code{triangle} (both the same as +## @code{linear}) are also supported. ## ## @var{bbox} ## @itemize @w @@ -64,26 +59,20 @@ function [imgPost, H, valid] = imrotate (imgPre, thetaDeg, interp = "nearest", bbox = "loose", extrapval = NA) - if (nargin < 2) - print_usage(); + if (nargin < 2 || nargin > 5) + print_usage (); elseif (! isimage (imgPre) || (! isrgb (imgPre) && ! isgray (imgPre))) error ("imrotate: IMGPRE must be a grayscale or RGB image.") elseif (! isscalar (thetaDeg)) error("imrotate: THETA must be a scalar"); elseif (! ischar (interp)) error("imrotate: interpolation METHOD must be a character array"); - elseif (! any (strcmpi (interp, {"nearest", "linear", "bilinear", "cubic", "bicubic", "Fourier"}))) - error("imrotate: unsupported METHOD interpolation method"); elseif (! isscalar (extrapval)) error("imrotate: EXTRAPVAL must be a scalar"); + elseif (! ischar (bbox) || ! any (strcmpi (bbox, {"loose", "crop"}))) + error("imrotate: BBOX must be 'loose' or 'crop'"); endif - - if (any(strcmpi(interp, {"bilinear", "bicubic"}))) - interp = interp(3:end); # Remove "bi" - endif - if (!any(strcmpi(bbox, {"loose", "crop"}))) - error("imrotate: bounding box must be either 'loose' or 'crop'"); - endif + interp = interp_method (interp); ## Input checking done. Start working thetaDeg = mod(thetaDeg, 360); # some code below relies on positive angles @@ -97,7 +86,7 @@ R = [cos(theta) sin(theta); -sin(theta) cos(theta)]; - if (nargin >= 4 && strcmp(bbox, "crop")) + if (nargin >= 4 && strcmpi(bbox, "crop")) sizePost = sizePre; else ## Compute new size by projecting zero-base image corner pixel @@ -153,8 +142,8 @@ end ## Now the actual rotations happen - if (strcmpi(interp, "Fourier")) - c = class (imgPre); + if (strcmpi (interp, "fourier")) + in_class = class (imgPre); imgPre = im2double (imgPre); if (isgray(imgPre)) imgPost = imrotate_Fourier(imgPre, thetaDeg, interp, bbox); @@ -165,14 +154,10 @@ endif valid = NA; - switch (c) - case "uint8" - imgPost = im2uint8 (imgPost); - case "uint16" - imgPost = im2uint16 (imgPost); - case "single" - imgPost = single (imgPost); - endswitch + ## we probably should do this in a safer way... but hardcoding the list of + ## im2xxxx functions might not be a good idea since it then it requires to + ## be added here if a new im2xxx function is implemented + imgPost = feval (["im2" in_class], imgPost); else [imgPost, valid] = imperspectivewarp(imgPre, H, interp, bbox, extrapval); endif @@ -181,10 +166,6 @@ function fs = imrotate_Fourier (f, theta, method, bbox) - if (size (f, 3) != 1) - error("imrotate_Fourier: image argument must be a gray-scale image"); - endif - # Get original dimensions. [ydim_orig, xdim_orig] = size(f);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/image/inst/private/interp_method.m Sat Jan 12 15:50:13 2013 +0000 @@ -0,0 +1,30 @@ +## Copyright (C) 2013 Carnë Draug <carandraug+dev@gmail.com> +## +## 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/>. + +## This private function is to be common to all functions that have an option +## for the interpolation method to use. For matlab compatibility, bicubic and +## bilinear are accepted which are the same as cubic and linear. This does not +## actually check if the method is valid, we leave that to interp2. The reason +## is that if interp2 implements a new method, all this functions will +## automatically work with it. + +function method = interp_method (method) + method = tolower (method); + switch method + case "bicubic", method = "cubic"; + case "bilinear", method = "linear"; + case "triangle", method = "linear"; # interpolation kernel + endswitch +endfunction