¿Es correcta mi perspectiva matemática?

24

Tengo una tarea en la que tengo que calcular y trazar algunos puntos usando una transformación pespectiva, pero no estoy seguro de que mis resultados sean correctos, ya que la trama 3D con coordenadas de cámara se ve muy diferente de la trama 2d con las coordenadas de la imagen . ¿Me pueden ayudar a entender qué pasa?

Esto es lo que se da: la cámara está en el punto W T C = [ - 1 , 1 , 5 ] T , especificada en coordenadas mundiales (en metros). El sistema de coordenadas de la cámara gira alrededor del eje Y de la referencia mundial en θ = 160 o , por lo que su matriz de rotación es w R c = [ c o s ( θ ) 0 s i n ( θ ) 0 1 0 - s i n (WTdo=[-1,1,5 5]Tθ=160owRdo=[doos(θ)0 0syonorte(θ)0 010 0-syonorte(θ)0 0doos(θ)]

Los parámetros de la cámara son: , s x = s y = 0.01 m m / p x , o x = 320 p x , o y = 240 p xF=dieciséismetrometrosX=sy=0,01metrometro/ /pagsXoX=320pagsXoy=240pagsX

Puntos de muestra (en coordenadas mundiales):

WPAGS1=[1,1,0.5 0.5]T

WPAGS2=[1,1,5,0.5 0.5]T

WPAGS3=[1,5,1,5,0.5 0.5]T

WPAGS4 4=[1,5,1,0.5 0.5]T

Tengo que calcular y trazar los puntos en las coordenadas de la cámara y en las coordenadas de la imagen, así que escribí el siguiente código en Octave:

%camera intrinsic parameters
f = 16
Sx = 0.01
Sy = 0.01
Ox = 320
Oy = 240

%given points, in world coordinate
wP1 = transpose([1, 1, 0.5])
wP2 = transpose([1, 1.5, 0.5])
wP3 = transpose([1.5, 1.5, 0.5])
wP4 = transpose([1.5, 1, 0.5])

% camera translation matrix
wTc = transpose([-1, 1, 5])

% rotation angle converted to rad
theta = 160 / 180 * pi

%camera rotation matrix
wRc = transpose([cos(theta), 0, sin(theta); 0, 1, 0; -sin(theta), 0, cos(theta)])

%transform the points to homogeneous coordinates
wP1h = [wP1; 1]
wP2h = [wP2; 1]
wP3h = [wP3; 1]
wP4h = [wP4; 1]

%separate each line of the rotation matrix
R1 = transpose(wRc(1 , :))
R2 = transpose(wRc(2 , :))
R3 = transpose(wRc(3 , :))

%generate the extrinsic parameters matrix
Mext = [wRc, [-transpose(R1) * wTc; -transpose(R2) * wTc; -transpose(R3) * wTc]]

%intrinsic parameters matrix
Mint = [-f/Sx, 0, Ox; 0, -f/Sy, Oy; 0, 0, 1]

% calculate coordinates in camera coordinates
cP1 = wRc * (wP1 - wTc)
cP2 = wRc * (wP2 - wTc)
cP3 = wRc * (wP3 - wTc)
cP4 = wRc * (wP4 - wTc)

% put coordinates in a list for plotting

x = [cP1(1), cP2(1), cP3(1), cP4(1), cP1(1)]
y = [cP1(2), cP2(2), cP3(2), cP4(2), cP1(2)]
z = [cP1(3), cP2(3), cP3(3), cP4(3), cP1(3)]

%plot the points in 3D using camera coordinates
plot3(x, y, z, "o-r")

pause()

% calculate the points in image coordinates
iP1 = Mint * (Mext * wP1h)
iP2 = Mint * (Mext * wP2h)
iP3 = Mint * (Mext * wP3h)
iP4 = Mint * (Mext * wP4h)

%generate a list of points for plotting
x = [iP1(1) / iP1(3), iP2(1) / iP2(3), iP3(1) / iP3(3), iP4(1) / iP4(3), iP1(1) / iP1(3)]
y = [iP1(2) / iP1(3), iP2(2) / iP2(3), iP3(2) / iP3(3), iP4(2) / iP4(3), iP1(2) / iP1(3)]

plot(x, y, "o-r")

pause()

Y estas son las tramas que obtuve del guión: esperaba que fueran algo similares, pero no lo parecen.

Trama 3D

Trazar en coordenadas de cámara

Trama 2D

Trazar en coordenadas de imagen

Vitor
fuente
8
+1 por mostrar que las preguntas de tarea pueden ser preguntas de alta calidad. :)
Martin Ender
2
Como se señaló en meta, esta pregunta merece una buena respuesta. Yo no tengo uno, pero estoy feliz de darle algo de mi reputación a alguien que sí.
trichoplax
@trichoplax el problema es que se hace en matlab.
joojaa
@joojaa ah buen punto. Si ningún experto en matlab interviene durante el período de recompensa, consideraré aprender Octave para ver si está lo suficientemente cerca como para encontrar una solución.
trichoplax
1
No me queda muy claro qué se supone que significa la primera imagen. El segundo es desde el punto de vista de la cámara, y después de una estimación posterior del sobre, creo que parece correcto.
Julien Guertault

Respuestas:

8

Identificar sus ejes en ambas figuras y agregar la posición de la cámara a su primera figura lo ayudaría a comprender lo que está sucediendo.

Xyz . De esa manera, podría manejar la proyección usando una simple multiplicación de matriz en lugar de manejar cada fila por separado.

[0 0,0 0,1][0 0,1,0 0] . Si alguno de esos supuestos es incorrecto, el resto de la respuesta será incorrecta.

0,016SX=Sy=0,00010.00001

[-1,1,X]z=0.5 0.5Xtunanorte(160°)(5 5-0.5 0.5)=1.64 ...X=-10,64yy

Una buena manera de verificar su respuesta es utilizando un modelador 3D existente como Blender: Escena 3D en Blender tenga cuidado con el sistema de coordenadas de Blender, por ejemplo, el vector de cámara predeterminado es [0, 0, -1]. Aquí está el render: Renderizar en Blender Focal se estableció en otro valor para hacer que la esfera sea más visible. Entonces vemos que los dos puntos inferiores están en la fila central de la imagen y los puntos están ligeramente a la derecha de la imagen.

Implementé tu tarea en Python:

import numpy as np

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import axes3d, Axes3D


# Parameters
f_mm = 0.016
f_px = f_mm / 0.00001
t_cam = np.array([[-1., 1., 5.]]).T
t_cam_homogeneous = np.vstack((t_cam, np.array([[0]])))
theta = 160. * np.pi / 180.
ox = 320
oy = 240
# Rotation and points are in homogeneous coordinates
rot_cam = np.array([[np.cos(theta), 0, np.sin(theta)],
                    [0, 1, 0],
                    [-np.sin(theta), 0, np.cos(theta)]])
points = np.array([[1, 1, 0.5, 1],
                   [1, 1.5, 0.5, 1],
                   [1.5, 1.5, 0.5, 1],
                   [1.5, 1, 0.5, 1]]).T

# Compute projection matrix using intrinsics and extrinsics
intrinsics = np.array([[f_px, 0, ox],
                       [0, f_px, oy],
                       [0, 0, 1]])
extrinsics = np.hstack((rot_cam, rot_cam.dot(-t_cam)))

rot_cam2 = np.identity(4); rot_cam2[:3,:3] = rot_cam
camera_coordinates = rot_cam2.dot(points - t_cam_homogeneous)
camera_coordinates = camera_coordinates[:3,:] / camera_coordinates[3,:]

# Perform the projection
projected_points = intrinsics.dot(camera_coordinates)
projected_points = projected_points[:2,:] / projected_points[2,:]
projected_points[0,:] = -projected_points[0,:] # Inverted x-axis because camera is pointing toward [0, 0, 1]

fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(points[0,:], points[1,:], points[2,:], label="Points")
ax.scatter(t_cam[0], t_cam[1], t_cam[2], c="red", label="Camera")
ax.set_xlabel("X axis"); ax.set_ylabel("Y axis"); ax.set_zlabel("Z axis")
plt.title("World coordinates")
plt.legend()
plt.savefig('world_coordinates.png', dpi=300, bbox_inches="tight")

fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(camera_coordinates[0,:], camera_coordinates[1,:], camera_coordinates[2,:], label="Points")
ax.scatter(0, 0, 0, c="red", label="Camera")
ax.set_xlabel("X axis"); ax.set_ylabel("Y axis"); ax.set_zlabel("Z axis")
plt.title("Camera coordinates")
plt.legend()
plt.savefig('camera_coordinates.png', dpi=300, bbox_inches="tight")

plt.figure()
plt.scatter(projected_points[0,:], projected_points[1,:])
plt.xlabel("X axis"); plt.ylabel("Y axis")
plt.title("Image coordinates")
plt.savefig('image_coordinates.png', dpi=300, bbox_inches="tight")

plt.show()

Esto me da esas cifras: respectivamente: coordenadas mundiales, coordenadas de la cámara, coordenadas de la cámara giradas para ajustarse ligeramente a la orientación de la cámara (tenga en cuenta que aquí el vector de la cámara va hacia el punto de vista de la figura, no "ingresa" la figura) y las coordenadas de la imagen.Coordenadas mundiales Coordenadas de la cámara Coordenadas de la cámara rotadas Coordenadas de imagen

Entonces, vemos que las coordenadas verticales para los puntos inferiores están correctamente en la fila central (240) y los puntos están en el lado derecho de la imagen (valor horizontal> 320).

-f/Sxy[0 0,0 0,1]X

[0 0,-1,0 0]

Soravux
fuente