I would like to rotate a non-squared image with Matlab:
imrotate
function, since it is part of the Image Processing Toolbox,loose
parameter, which means the size of the output differs from the size of the input image,imrotate
.I have already found a function in order to do this (just replace imshow
and bestblk
with your own functions in order not to use the toolbox), yet it is really slow for large images. My approach would try to avoid making loops and relying as much as possible on interp2
.
The signature of the function would be:
imOutput = my_imrotate(imInput, theta_degres, interpolation, bbox)
where:
interpolation
would be bilinear
, bicubic
or nearest
,bbox
would be crop
, or loose
.Crop
I already have a good result with the crop
parameter, but I cannot manage to find the offset for the loose
parameter.
Here is the code for the crop
parameter, where Z
is the input and Zi
is the output:
Z = double(imInput);
sz = size(Z);
[X,Y] = meshgrid(1:sz(2), 1:sz(1));
%# Center
c = sz(end:-1:1)/2;
%# Angle
t = theta_degres*pi/180;
%# Rotation
ct = cos(t);
st = sin(t);
Xi = c(1) + ct*(X-c(1))-st*(Y-c(2));
Yi = c(2) + st*(X-c(1))+ct*(Y-c(2));
%# Rotation
Zi = interp2(X, Y, Z, Xi, Yi);
Loose
My idea is to compute the size of a frame which would contain the original image as well as the rotated image, and then:
interp2
on the padded image,To get the size of the rotated image with the loose
parameter, I compute the rotation_matrix
and call rotate_points
on the coordinates of the corners p
of the input image:
rotation_matrix = [ct, -st; st, ct];
rotate_points = @(p) bsxfun(@plus, c', rotation_matrix * bsxfun(@minus, p, c)')';
Any help would be highly appreciated.
Edit: Using the solution provided in the answer below, and the following code, it seems to work quite right:
%# See the answer below
[sz1,sz2] = size(Z);
sz1New = sz1*cos(t)+sz2*sin(t);
sz2New = sz2*cos(t)+sz1*sin(t);
[Xi,Yi] = meshgrid(-(sz2New-1)/2:(sz2New-1)/2,-(sz1New-1)/2:(sz1New-1)/2);
%# now all that's left is rotating Xi,Yi - I have already subtracted the center
%# My little piece of additional code
Xii = (1+sz2)/2 + ct*Xi - st*Yi;
Yii = (1+sz1)/2 + st*Xi + ct*Yi;
Zi = interp2(X, Y, Z, Xii, Yii);
For the loose
version, all you need to do is find out how much padding you need. You can estimate it easily with a little bit of geometry:
If you draw the 'loose' rectangle, you're essentially adding four right angle triangles to the original rectangle. The hypotenuse of the triangles are the sides of the rectangle. If you can determine the other two sides, you can easily calculate the length of the new sides and thus the padding. Fortunately, one of the angles of the right triangle is exactly your rotation angle.
As it turns out, you don't even need to calculate the padding explicitly - you simply create a larger array Xi,Yi that has the size of the 'loose' image.
Thus:
[sz1,sz2] = size(Z);
sz1New = sz1*cos(t)+sz2*sin(t);
sz2New = sz2*cos(t)+sz1*sin(t);
[Xi,Yi] = meshgrid(-(sz2New-1)/2:(sz2New-1)/2,-(sz1New-1)/2:(sz1New-1)/2);
%# now all that's left is rotating Xi,Yi - I have already subtracted the center