2012-02-08 14 views
7

Estoy tratando de obtener algún código que realice una transformación de perspectiva (en este caso, una rotación en 3D) en una imagen.rotación en 3D en la imagen

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) 

Cuando gire alrededor del eje z, todo funciona como se esperaba, sino que gira alrededor del eje X o Y parece completamente fuera. Necesito rotar en ángulos tan pequeños como pi/200 antes de comenzar a obtener resultados que parecen del todo razonables. ¿Alguna idea de lo que podría estar mal?

Respuesta

21

En primer lugar, la construcción de la matriz de rotación, de la forma

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

La aplicación de esta coordenada transformar le da una rotación alrededor del origen.

Si, por el contrario, desea rotar alrededor del centro de la imagen, primero debe desplazar el centro de la imagen al origen, luego aplicar la rotación y luego volver a colocar todo. Puede hacerlo a través de una matriz traducción:

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

La matriz de transformación de traslación, rotación y traslación inversa entonces se convierte en:

H = inv(T) * R * T 

voy a tener que pensar un poco acerca de cómo relacionarse la matriz oblicua a la transformación 3D. Espero que la ruta más fácil sea configurar una matriz de transformación 4D y luego proyectarla de nuevo a coordenadas homogéneas 2D. Pero por ahora, la forma general de la matriz de inclinación:

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

Los x_skew y y_skew valores son típicamente muy pequeña (1e-3 o menos).

Aquí está el código:

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

Y la salida:

Rotations of cameraman around origin and center+skew

0

No entiendo la forma en que construyes tu matriz de rotación. Me parece bastante complicado. Generalmente, se construiría construyendo una matriz cero, poniendo 1 en ejes innecesarios, y el sin, cos, -cos, sin común en las dos dimensiones utilizadas. Luego multiplicando todos estos juntos.

¿De dónde sacaste esa construcción np.eye(3) + np.sin(angle) * skew(axis) + (1 - np.cos(angle)) * skew(axis).dot(skew(axis))?

Intente construir la matriz de proyección a partir de bloques de construcción básicos. Construir una matriz de rotación es bastante fácil, y "rotationmatrix dot skewmatrix" debería funcionar.

Sin embargo, es posible que deba prestar atención al centro de rotación. Es probable que su imagen se coloque en una posición virtual de 1 en el eje z, por lo que al girar en x o y, se mueve un poco. Así que necesitaría usar una traducción para que z se convierta en 0, luego girar, luego traducir de nuevo. (Matrices de Traducción en coordenadas afines son bastante simples, también vea Wikipedia:. https://en.wikipedia.org/wiki/Transformation_matrix)

Cuestiones relacionadas