2012-02-08 164 views
7

我想要获得一些代码,将在图像上执行透视变换(在这种情况下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轴旋转似乎完全关闭。在我开始得到完全合理的结果之前,我需要旋转π/ 200这样小的角度。任何想法可能是错的?

回答

21

首先,建立形式

[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_skewy_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() 

和输出:

Rotations of cameraman around origin and center+skew

0

我不明白你建立旋转矩阵的方式。这对我来说似乎相当复杂。通常,它将通过构建零矩阵,将不需要的轴上的1,以及将常见的sincos,-cos,sin分解为两个使用的维度。然后将所有这些相乘。

从哪里得到np.eye(3) + np.sin(angle) * skew(axis) + (1 - np.cos(angle)) * skew(axis).dot(skew(axis))构建?

尝试从基本构建模块构建投影矩阵。构造一个旋转矩阵相当容易,并且“rotationmatrix dot skewmatrix”应该可以工作。

虽然您可能需要注意旋转中心。您的图像可能位于z轴上的虚拟位置1处,因此通过在x或y上旋转,它会移动一点。 所以你需要使用翻译,所以z变为0,然后旋转,然后回转。 (在仿射坐标转换矩阵是相当简单,太见维基百科:https://en.wikipedia.org/wiki/Transformation_matrix