图像的3D旋转
我正在尝试写一些代码,用来对一张图片进行透视变换(在这个例子中是3D旋转)。
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)
当我围绕z轴旋转时,一切都按预期工作,但围绕x轴或y轴旋转时,结果看起来完全不对。我需要旋转到像pi/200这么小的角度,才能开始得到看起来合理的结果。你知道可能出什么问题了吗?
2 个回答
我不太明白你是怎么构建你的旋转矩阵的。对我来说,这看起来有点复杂。通常,构建旋转矩阵的方法是先创建一个零矩阵,然后在不需要的轴上放上 1
,在需要的两个维度中放入常见的 sin
、cos
、-cos
和 sin
。最后把这些组合在一起。
你是从哪里得到这个 np.eye(3) + np.sin(angle) * skew(axis) + (1 - np.cos(angle)) * skew(axis).dot(skew(axis))
的构造方式的?
试着从基本的构建块来构建投影矩阵。构建旋转矩阵其实很简单,"旋转矩阵 乘以 倾斜矩阵"应该是可行的。
不过你可能需要注意旋转的中心。你的图像可能在 z 轴上虚拟位置为 1,所以在 x 或 y 轴上旋转时,它会稍微移动一下。因此你需要先进行平移,让 z 变成 0,然后再旋转,最后再平移回来。(在仿射坐标系中,平移矩阵也很简单。可以看看维基百科:https://en.wikipedia.org/wiki/Transformation_matrix)
首先,构建一个旋转矩阵,它的形式是
[cos(theta) -sin(theta) 0]
R = [sin(theta) cos(theta) 0]
[0 0 1]
应用这个坐标变换可以让你围绕原点进行旋转。
如果你想围绕图像中心旋转,首先需要把图像中心移动到原点,然后进行旋转,最后再把一切移回去。你可以使用一个平移矩阵来做到这一点:
[1 0 -image_width/2]
T = [0 1 -image_height/2]
[0 0 1]
那么,平移、旋转和逆平移的变换矩阵就变成了:
H = inv(T) * R * T
我还需要想一想如何将斜切矩阵与3D变换联系起来。我认为最简单的方法是建立一个4D变换矩阵,然后再将其投影回2D齐次坐标。不过现在,斜切矩阵的一般形式是:
[x_scale 0 0]
S = [0 y_scale 0]
[x_skew y_skew 1]
x_skew
和 y_skew
的值通常很小(1e-3或更小)。
这里是代码:
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()
输出结果是: