2012-02-08 192 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