function [rout,g,b] = imrotate(varargin)
%IMROTATE Rotate image.
% B = IMROTATE(A,ANGLE,'method') rotates the image A by ANGLE
% degrees. The image returned B will, in general, be larger
% than A. Invalid values on the periphery are set to one
% for indexed images or zero for all other image types. Possible
% interpolation methods are 'nearest' (nearest neighbor),
% 'bilinear' or 'bicubic'. 'nearest' is the default for all
% images. For indexed images, only nearest-neighbor interpolation
% should be used. A can also be an M x N x 3 RGB truecolor image.
%
% B = IMROTATE(A,ANGLE,'crop') or IMROTATE(A,ANGLE,'method','crop')
% crops B to be the same size as A.
%
% Without output arguments, IMROTATE(...) displays the rotated
% image in the current axis.
%
% See also IMRESIZE, IMCROP, ROT90.
% Clay M. Thompson 8-4-92
% Copyright (c) 1992 by The MathWorks, Inc.
% $Revision: 5.4 $ $Date: 1996/10/23 19:34:48 $
[Image,Angle,Method,ClassIn,DoCrop] = parse_inputs(varargin{:});
threeD = (ndims(Image)==3); % Determine if input includes a 3-D array
if threeD,
r = rotateImage(Image(:,:,1),Angle,Method,DoCrop);
g = rotateImage(Image(:,:,2),Angle,Method,DoCrop);
b = rotateImage(Image(:,:,3),Angle,Method,DoCrop);
if nargout==0,
imshow(r,g,b);
return;
elseif nargout==1,
if strcmp(ClassIn,'uint8');
rout = repmat(uint8(0),[size(r),3]);
rout(:,:,1) = uint8(round(r*255));
rout(:,:,2) = uint8(round(g*255));
rout(:,:,3) = uint8(round(b*255));
else
rout = zeros([size(r),3]);
rout(:,:,1) = r;
rout(:,:,2) = g;
rout(:,:,3) = b;
end
else % nargout==3
if strcmp(ClassIn,'uint8')
rout = uint8(round(r*255));
g = uint8(round(g*255));
b = uint8(round(b*255));
else
rout = r; % g,b are already defined correctly above
end
end
else
r = rotateImage(Image,Angle,Method,DoCrop);
if nargout==0,
imshow(r);
return;
end
if strcmp(ClassIn,'uint8')
r = uint8(round(r*255));
end
rout = r;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function: rotateImage
%
function b = rotateImage(A,ang,method,crop)
% Inputs:
% A Input Image
% ang Angle to rotate image by
% method 'nearest','bilinear', or 'bicubic'
% crop 1 to crop image, 0 will output entire rotated image
% Catch and speed up 90 degree rotations
if rem(ang,90)==0 & nargin<4,
phi = round(ang - 360*floor(ang/360));
if phi==90,
b = rot90(A);
elseif phi==180,
b = rot90(A,2);
elseif phi==270,
b = rot90(A,-1);
else
b = A;
end
if nargout==0, imshow(b), else bout = b; end
return
end
phi = ang*pi/180; % Convert to radians
% Rotation matrix
T = [cos(phi) -sin(phi); sin(phi) cos(phi)];
% Coordinates from center of A
[m,n,o] = size(A);
if ~crop, % Determine limits for rotated image
siz = ceil(max(abs([(n-1)/2 -(m-1)/2;(n-1)/2 (m-1)/2]*T))/2)*2;
uu = -siz(1):siz(1); vv = -siz(2):siz(2);
else % Cropped image
uu = (1:n)-(n+1)/2; vv = (1:m)-(m+1)/2;
end
nu = length(uu); nv = length(vv);
blk = bestblk([nv nu]);
nblks = floor([nv nu]./blk); nrem = [nv nu] - nblks.*blk;
mblocks = nblks(1); nblocks = nblks(2);
mb = blk(1); nb = blk(2);
rows = 1:blk(1); b = zeros(nv,nu);
for i=0:mblocks,
if i==mblocks, rows = (1:nrem(1)); end
for j=0:nblocks,
if j==0, cols = 1:blk(2); elseif j==nblocks, cols=(1:nrem(2)); end
if ~isempty(rows) & ~isempty(cols)
[u,v] = meshgrid(uu(j*nb+cols),vv(i*mb+rows));
% Rotate points
uv = [u(:) v(:)]*T'; % Rotate points
u(:) = uv(:,1)+(n+1)/2; v(:) = uv(:,2)+(m+1)/2;
if method(1)=='n', % Nearest neighbor interpolation
b(i*mb+rows,j*nb+cols) = interp2(A,u,v,'*nearest');
elseif all(method=='bil'), % Bilinear interpolation
b(i*mb+rows,j*nb+cols) = interp2(A,u,v,'*linear');
elseif all(method=='bic'), % Bicubic interpolation
b(i*mb+rows,j*nb+cols) = interp2(A,u,v,'*cubic');
else
error(['Unknown interpolation method: ',method]);
end
end
end
end
d = find(isnan(b));
if length(d)>0,
% The next line is a hack so we won't have to do the whole isind check if
% we can see from the first 10 pixels that it is not indexed.
if (isind(A(1:min(10,end))) & isind(A)),
b(d) = 1;
else
b(d) = 0;
end
end
if isgray(A) % This should always be true
b = max(0,min(b,1));
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function: parse_inputs
%
function [A,Angle,Method,Class,CropIt] = parse_inputs(varargin)
% Outputs: A the input image
% Angle the angle by which to rotate the input image
% Method interpolation method (nearest,bilinear,bicubic)
% Class storage class of A
A = varargin{1};
Angle = varargin{2};
Class = class(A);
switch nargin
case 2, % imrotate
Method = 'nea';
CropIt = 0;
case 3,
if isstr(varargin{3}),
Method = [lower(varargin{3}),' ']; % Protect against short method
Method = Method(1:3);
if Method(1)=='c', % Crop string
Method = 'nea';
CropIt = 1;
else
CropIt = 0;
end
else
error('''METHOD'' must be a string of at least three characters.');
end
case 4,
if isstr(varargin{3}),
Method = [lower(varargin{3}),' ']; % Protect against short method
Method = Method(1:3);
else
error('''METHOD'' must be a string of at least three characters.');
end
CropIt = 1;
otherwise,
error('Invalid input arguments');
end
if isa(A, 'uint8'), % Convert A to Double grayscale for filtering & interpolation
A = double(A)/255;
end