2012-02-08 15 views
7

Sto cercando di ottenere del codice che eseguirà una trasformazione prospettica (in questo caso una rotazione 3d) su un'immagine.rotazione 3D sull'immagine

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) 

Quando ruotare attorno all'asse z, tutto funziona come previsto, ma ruotando attorno all'asse xoy sembra completamente fuori. Ho bisogno di ruotare di angoli piccoli come il pi/200 prima di iniziare a ottenere risultati che sembrano del tutto ragionevoli. Qualche idea di cosa potrebbe essere sbagliato?

risposta

21

In primo luogo, costruire la matrice di rotazione, della forma

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

L'applicazione di questa coordinata trasformare ti dà una rotazione attorno all'origine.

Se, invece, si desidera ruotare attorno al centro dell'immagine, è necessario innanzitutto spostare il centro dell'immagine all'origine, quindi applicare la rotazione e quindi spostare indietro tutto. È possibile farlo utilizzando una matrice traduzione:

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

La matrice di trasformazione per la traduzione, rotazione e la conversione inversa diviene quindi:

H = inv(T) * R * T 

io dovrò pensare un po 'su come mettere in relazione la matrice di inclinazione alla trasformazione 3D. Mi aspetto che il percorso più semplice sia quello di impostare una matrice di trasformazione 4D e quindi di proiettarla su coordinate omogenee 2D. Ma per ora, la forma generale della matrice skew:

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

I x_skew e y_skew valori sono tipicamente piccolo (1e-3 o meno).

Ecco il codice:

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

E l'output:

Rotations of cameraman around origin and center+skew

0

Non capisco come si costruisce la matrice di rotazione. Mi sembra piuttosto complicato. Di solito, sarebbe costruito costruendo una matrice zero, mettendo 1 su assi non necessari, e il comune sin, cos, -cos, sin nelle due dimensioni utilizzate. Quindi moltiplicando tutti questi insieme.

Da dove viene il costrutto np.eye(3) + np.sin(angle) * skew(axis) + (1 - np.cos(angle)) * skew(axis).dot(skew(axis))?

Provare a costruire la matrice di proiezione dai blocchi di base. Costruire una matrice di rotazione è abbastanza facile, e "rotationmatrix dot skewmatrix" dovrebbe funzionare.

Potrebbe tuttavia essere necessario prestare attenzione al centro di rotazione. L'immagine viene probabilmente posizionata in una posizione virtuale di 1 sull'asse z, quindi ruotando su x o su y, si sposta di un bit. Quindi è necessario utilizzare una traduzione in modo che z diventi 0, quindi ruoti, quindi traduca indietro. (Matrici di traduzione in coordinate affini sono abbastanza semplici, anche vedi Wikipedia:. https://en.wikipedia.org/wiki/Transformation_matrix)

Problemi correlati