Rotating an image without the Image Processing Toolbox

Wok picture Wok · Jun 15, 2011 · Viewed 8.9k times · Source

I would like to rotate a non-squared image with Matlab:

  • without using the imrotate function, since it is part of the Image Processing Toolbox,
  • with the loose parameter, which means the size of the output differs from the size of the input image,
  • and with a not too slow function compared to 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:

  1. pad the original image so as to have an image whose size is the size of the frame,
  2. use interp2 on the padded image,
  3. crop the resulting image so as to have the rotated image without the remains of the padding.

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);

Answer

Jonas picture Jonas · Jun 15, 2011

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