11

I'm trying to get some code that will perform a perspective transformation (in this case a 3d rotation) on an image.

import os.path import numpy as np import cv def rotation(angle, axis): return np.eye(3) + np.sin(angle) * skew(axis) \ + (1 - np.cos(angle)) * skew(axis).dot(skew(axis)) def skew(vec): return np.array([[0, -vec[2], vec[1]], [vec[2], 0, -vec[0]], [-vec[1], vec[0], 0]]) def rotate_image(imgname_in, angle, axis, imgname_out=None): if imgname_out is None: base, ext = os.path.splitext(imgname_in) imgname_out = base + '-out' + ext img_in = cv.LoadImage(imgname_in) img_size = cv.GetSize(img_in) img_out = cv.CreateImage(img_size, img_in.depth, img_in.nChannels) transform = rotation(angle, axis) cv.WarpPerspective(img_in, img_out, cv.fromarray(transform)) cv.SaveImage(imgname_out, img_out) 

When I rotate about the z-axis, everything works as expected, but rotating around the x or y axis seems completely off. I need to rotate by angles as small as pi/200 before I start getting results that seem at all reasonable. Any idea what could be wrong?

2 Answers 2

29

First, build the rotation matrix, of the form

 [cos(theta) -sin(theta) 0] R = [sin(theta) cos(theta) 0] [0 0 1] 

Applying this coordinate transform gives you a rotation around the origin.

If, instead, you want to rotate around the image center, you have to first shift the image center to the origin, then apply the rotation, and then shift everything back. You can do so using a translation matrix:

 [1 0 -image_width/2] T = [0 1 -image_height/2] [0 0 1] 

The transformation matrix for translation, rotation, and inverse translation then becomes:

H = inv(T) * R * T 

I'll have to think a bit about how to relate the skew matrix to the 3D transformation. I expect the easiest route is to set up a 4D transformation matrix, and then to project that back to 2D homogeneous coordinates. But for now, the general form of the skew matrix:

 [x_scale 0 0] S = [0 y_scale 0] [x_skew y_skew 1] 

The x_skew and y_skew values are typically tiny (1e-3 or less).

Here's the code:

from skimage import data, transform import numpy as np import matplotlib.pyplot as plt img = data.camera() theta = np.deg2rad(10) tx = 0 ty = 0 S, C = np.sin(theta), np.cos(theta) # Rotation matrix, angle theta, translation tx, ty H = np.array([[C, -S, tx], [S, C, ty], [0, 0, 1]]) # Translation matrix to shift the image center to the origin r, c = img.shape T = np.array([[1, 0, -c / 2.], [0, 1, -r / 2.], [0, 0, 1]]) # Skew, for perspective S = np.array([[1, 0, 0], [0, 1.3, 0], [0, 1e-3, 1]]) img_rot = transform.homography(img, H) img_rot_center_skew = transform.homography(img, S.dot(np.linalg.inv(T).dot(H).dot(T))) f, (ax0, ax1, ax2) = plt.subplots(1, 3) ax0.imshow(img, cmap=plt.cm.gray, interpolation='nearest') ax1.imshow(img_rot, cmap=plt.cm.gray, interpolation='nearest') ax2.imshow(img_rot_center_skew, cmap=plt.cm.gray, interpolation='nearest') plt.show() 

And the output:

Rotations of cameraman around origin and center+skew

Sign up to request clarification or add additional context in comments.

Comments

0

I do not get the way you build your rotation matrix. It seems rather complicated to me. Usually, it would be built by constructing a zero matrix, putting 1 on unneeded axes, and the common sin, cos, -cos, sin into the two used dimensions. Then multiplying all these together.

Where did you get that np.eye(3) + np.sin(angle) * skew(axis) + (1 - np.cos(angle)) * skew(axis).dot(skew(axis)) construct from?

Try building the projection matrix from basic building blocks. Constructing a rotation matrix is fairly easy, and "rotationmatrix dot skewmatrix" should work.

You might need to pay attention to the rotation center though. Your image probably is placed at a virtual position of 1 on the z axis, so by rotating on x or y, it moves around a bit. So you'd need to use a translation so z becomes 0, then rotate, then translate back. (Translation matrixes in affine coordinates are pretty simple, too. See wikipedia: https://en.wikipedia.org/wiki/Transformation_matrix )

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.