function varargout = imregrotate(varargin)
%ROIROTATE Rotate & crop region of interest avoiding 'black corners'.
% 	B = ROIROTATE(A,ROI,ANGLE,METHOD) rotates the region of intererest ROI
% 	found in the image A by ANGLE degrees in a counter-clockwise direction, 
% 	using the specified interpolation method and gives the rotated 
% 	region as output in B cropped out of the original image.
% 	
% 	Usefulness
% 	----------
% 	ROIROTATE was designed to avoid the 'black corners' typical of
%   MATLAB's imrotate function, which are apearing from its behaviour
%   of padding by zeros the space outside the image borders prior to 
%   the rotation. This is possible if the image to be rotated is 
%   part of a bigger image - which is the definition of a 'region 
%   of interest' -, because there is enough information to fill 
%   the corners.
% 	
% 	Description
% 	-----------
% 	Apart of the first entry which is based on the IMCROP syntax, 
% 	all other are identical to the IMROTATE function.
% 	
%   ROI is a four-element vector with the form [xmin ymin width height];
%   these values are specified in spatial coordinates.
% 	
% 	xmin - starting pixel to be cut, x-th of the original image
% 	ymin - same on y-axis
% 	width - number of pixels to be cut minus one (width)
% 	height - same on height
% 	
% 	If you want to point the 5 pixel wide & 7 pixel heigh NW corner 
% 	of an image, replace R with [1,1,4,6].
% 	
%   Because ROI is specified in terms of spatial coordinates,
%   the WIDTH and HEIGHT of ROI do not always correspond exactly
%   with the size of the output image. For example, suppose ROI
%   is [20 20 40 30], using the default spatial coordinate
%   system. The upper left corner of the specified rectangle is
%   the center of the pixel (20,20) and the lower right corner is
%   the center of the pixel (50,60). The resulting output image
%   is 31-by-41, not 30-by-40, because the output image includes
%   all pixels in the input that are completely or partially
%   enclosed by the rectangle.
% 	
%         Note for IMCROP:
%         To cut the NW pixel only:
%             NWcornerPixel = imcrop(I, [1,1,0,0]);
%         
%         To cut the first top stripe of pixels:
%             topStripe = imcrop(I, [1,1,size(I,2)-1,0]);
% 	
% 	METHOD is a string that can have one of these values:
% 	
%        'nearest'  (default) nearest neighbor interpolation
%        'bilinear' bilinear interpolation
%        'bicubic'  bicubic interpolation
% 	
% 	If you omit the METHOD argument, ROIROTATE uses the default
% 	method of 'nearest'.
%
%   To rotate the image clockwise, specify a negative angle.
% 	
% 	Class Support
% 	-------------
% 	The input image can be of class uint8, uint16, or double.
%   The output image is of the same class as the input image.
% 	
% 	Example
% 	-------
%        I = imread('circuit.tif');
%        J = imrotate(imcrop(I,[60 80 100 90]),-21,'bilinear','crop');
%        [K x y w h] = roirotate(I,[60 80 100 90],-21,'bilinear');
%        figure, subplot(1,3,1), imshow(I), title('roi')
%        rectangle('Position',[60 80 100 90],'EdgeColor','red');
%        rectangle('Position',[x y w h],'EdgeColor','green');
%        subplot(1,3,2), imshow(J), title('imrotate')
%        subplot(1,3,3), imshow(K), title('roirotate')
%
% 	See also IMROTATE, IMCROP, IMRESIZE, IMTRANSFORM, TFORMARRAY.

%   Vlad Atanasiu - 06/05/2002
%   Revisions: 3  > 01/11/2008



% check image input data
[A,dim,x,y,width,height,ang,method] = parseInputs(varargin{:});

% calculate padding borders
padX = abs(ceil(height*sin(ang*pi/180)/2));
padY = abs(ceil(width*sin(ang*pi/180)/2));

% padding zeros if extended region of interest coordinates outside image
if x-padX < 1   % left
    A = [zeros(size(A,1),padX-x+1,dim) A];
end
if y-padY < 1   % top
    A = [zeros(padY-y+1,size(A,2),dim);...
            A];
end
if x+width+padX > size(A,2)   % right
    A = [A zeros(size(A,1),x+width+padX-size(A,2),dim)];
end
if y+height+padY > size(A,1)   % bottom
    A = [A;...
            zeros(y+height+padY-size(A,1),size(A,2),dim)];
end

% cut extended region
ROI = imcrop(A,[x-padX y-padY width+padX*2 height+padY*2]);

% rotate extended region
ROI = imrotate(ROI,ang,method,'crop');

% cut region
varargout{1} = imcrop(ROI,[padX padY width height]);

% gives extended region coordinates
if nargout == 5
    varargout{2} = x-padX;
    varargout{3} = y-padY;
    varargout{4} = width+padX*2;
    varargout{5} = height+padY*2;
end


% ------------------------------------------------

function [A,dim,x,y,width,height,ang,method] = parseInputs(varargin)
% Input checkings

% Defaults
method = 'n';

% Check number of input parameters
error(nargchk(3,4,nargin));
switch nargin
case 3,             % regrotate(A,reg,ang,)
    A = varargin{1};
	x = varargin{2}(1);
	y = varargin{2}(2);
	width = varargin{2}(3);
	height = varargin{2}(4);
    ang = varargin{3};
case 4,             % regrotate(A,reg,ang,method) 
    A = varargin{1};
	x = varargin{2}(1);
	y = varargin{2}(2);
	width = varargin{2}(3);
	height = varargin{2}(4);
    ang = varargin{3};
    method = varargin{4};
otherwise,
    error('Invalid number of input arguments.');
end

% Check validity of the input parameters 
if ischar(method),
    strings = {'nearest','bilinear','bicubic'};
    idx = strmatch(lower(method),strings);
    if isempty(idx),
        error(sprintf('Unknown interpolation method: %s',method));
    elseif length(idx)>1,
        error(sprintf('Ambiguous interpolation method: %s',method));
    else
        method = strings{idx};
    end  
else
    error('Interpolation method have to be a string.');  
end

if size(varargin{2},2) ~= 4
    error('Region of interest should be defined by 4 arguments.');  
end

% transforms the format of A into an image if it is a filename
if (isstr(A))
    A = imread(A);
end

% gets the dimensions of A
dim = ndims(A);
if dim == 2, dim=1; end

% modifies if needed the region of interest coordinates if outside image
if x < 1, x = 1; end
if y < 1, y = 1; end
if x > size(A,2)-1, x = size(A,2)-1; end
if y > size(A,1)-1, y = size(A,1)-1; end
if x+width > size(A,2)-1, width = size(A,2)-x-1; end
if y+height > size(A,1)-1, height = size(A,1)-y-1; end


