Para la proyección en perspectiva con matrices de cámara dadas y rotación y traslación, podemos calcular la coordenada de píxel 2D de un punto 3D.
utilizando la matriz de proyección,
dónde es matriz de cámara intrínseca, es rotación es traducción. La proyección es simple multiplicación de matrices. . Libro de Zisserman , pág. 161 sugiere usar matriz de proyección y toma de pseudoinversa. Entonces uno calcularía que definió hasta la escala que luego puede interpretarse como el rayo que comienza desde el centro de la cámara y va hasta el infinito. Rápidamente codifiqué esto, tomé como profundidad, así que traduje la cámara en dirección (hasta 1 metro), y después de recuperar volteado para trazar (la mayoría de las matemáticas geométricas proyectivas parecen estar construidas para hacer profundidad),
K = [[ 282.363047, 0., 166.21515189],
[ 0., 280.10715905, 108.05494375],
[ 0., 0., 1. ]]
K = np.array(K)
R = np.eye(3)
t = np.array([[0],[1],[0]])
P = K.dot(np.hstack((R,t)))
import scipy.linalg as lin
x = np.array([300,300,1])
X = np.dot(lin.pinv(P),x)
X = X / X[3]
from mpl_toolkits.mplot3d import Axes3D
w = 20
f = plt.figure()
XX = X[:]; XX[1] = X[2]; XX[2] = X[1]
ax = f.gca(projection='3d')
ax.quiver(0, 0, 1., XX[:3][0], XX[:3][1], XX[:3][2],color='red')
ax.set_xlim(0,10);ax.set_ylim(0,10);ax.set_zlim(0,10)
ax.quiver(0., 0., 1., 0, 5., 0.,color='blue')
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title(str(x[0])+","+str(x[1]))
ax.set_xlim(-w,w);ax.set_ylim(-w,w);ax.set_zlim(-w,w)
ax.view_init(elev=29, azim=-30)
fout = 'test_%s_01.png' % (str(x[0])+str(x[1]))
plt.savefig(fout)
ax.view_init(elev=29, azim=-60)
fout = 'test_%s_02.png' % (str(x[0])+str(x[1]))
plt.savefig(fout)
Estas imágenes a continuación son el resultado (la flecha azul muestra el vector normal perpendicular al plano de la imagen, las imágenes muestran todas las combinaciones x=10,300 y=10,300):
Doy el diagrama de cámara/rayo para cada píxel desde dos ángulos diferentes.
¿Estos resultados parecen sensatos? 10,10 y 200,200 parecían extraños, jugué un poco con los signos, si traduzco usando -1 negativo y usando -Z después de X calc., ¿las cosas mejoran un poco?
t = np.array([[0],[-1],[0]])
..
XX = X[:]; XX[1] = X[2]; XX[2] = -X[1]
No sé por qué es eso.
En lugar de tratar de depurar su código y verificar todas esas asignaciones inversas, describiré una forma de verificar sus propios resultados de manera objetiva. Si no tiene una buena idea de cuáles deberían ser los resultados, entonces realmente no veo cómo puede saber si son o no "razonables".
Asumiendo que no hay sesgo en la cámara, la matriz tiene la forma
En este caso concreto, es solo la matriz de identidad, por lo que no hay nada más que hacer una vez que tenga el vector de dirección en las coordenadas de la cámara. Tenemos
Aparte de todo eso, hay un problema cuando se usa el método pseudoinverso descrito por Zisserman. Da la siguiente ecuación para el rayo mapeado hacia atrás:
Para ilustrar, aplicar a produce , entonces el rayo es . En coordenadas cartesianas, el punto retroasignado es y restando la posición de la cámara da . Para comparar esto con el resultado conocido anterior, divida por la tercera coordenada: , que está de acuerdo.
Actualización 2018.07.31: Para cámaras finitas, que es con lo que estás tratando, Zisserman sugiere una retroproyección más conveniente en el siguiente párrafo de la ecuación (6.14). La idea subyacente es que se descompone la matriz de la cámara como para que la retroproyección de un punto de imagen corta al plano en el infinito en . Esto le da el vector de dirección del rayo retroproyectado en coordenadas mundiales y, por supuesto, el centro de la cámara está en , es decir, el rayo retroproyectado es
El método pseudoinverso funciona, a continuación se muestra el ejemplo para el píxel 215,180 (la esquina superior izquierda de la imagen es (0,0)), el rayo de este píxel va hacia la parte inferior derecha desde el punto de vista de una persona que mira desde el centro de la cámara hacia el eje Y. Debido al modelo de cámara estenopeica / proyección en perspectiva, fueron necesarios algunos cambios en el eje (pude cambiar mientras trazaba, pero el código a continuación es parte de otro análisis que tuve que realizar en un espacio 3D familiar).
from PIL import Image
from mpl_toolkits.mplot3d import Axes3D
import scipy.linalg as lin
K = [[ 282.363047, 0., 166.21515189],
[ 0., 280.10715905, 108.05494375],
[ 0., 0., 1. ]]
K = np.array(K)
R = np.eye(3)
t = np.array([[0],[1.],[0]])
P = K.dot(np.hstack((R,t)))
C = np.array([0., 0., 1.])
p1 = np.array([215, 180, 1.])
X = np.dot(lin.pinv(P),p1)
X = X / X[3]
XX = np.copy(X)
XX[1] = X[2]; XX[2] = X[1]; XX[2] = -XX[2]
w = 10
f = plt.figure()
ax = f.gca(projection='3d')
xvec = C - XX[:3]
xvec = -xvec
ax.quiver(C[0], C[1], C[2], xvec[0], xvec[1], xvec[2],color='red')
ax.set_xlim(0,10);ax.set_ylim(0,10);ax.set_zlim(0,10)
ax.quiver(0., 0., 1., 0, 5., 0.,color='blue')
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_xlim(-w,w);ax.set_ylim(-w,w);ax.set_zlim(-w,w)
ax.view_init(elev=5, azim=100)
plt.savefig('out1.png')
ax.view_init(elev=5, azim=50)
plt.savefig('out2.png')
Dado que este es el primer y único resultado de Google que realmente ayuda, y tomó bastante tiempo crearlo, aquí está en Numpy
import numpy as np
def convert_nx2_to_homo_3xn(points_nx2: np.array):
return np.hstack([points_nx2, np.ones((points_nx2.shape[0], 1))]).T
def convert_nx3_to_homo_4xn(points_nx3: np.array):
return np.hstack([points_nx3, np.ones((points_nx3.shape[0], 1))]).T
def cast_2d_points_as_3d_rays(sub_pixels_nx2: np.array, proj_3x4: np.array):
"""
see Harley & Zisserman pg 162, section 6.2.2, figure 6.14
see https://math.stackexchange.com/a/597489/541203
cast rays from camera center through the sub_pixels_nx2. Return camera center and ray directions.
"""
m_3x3 = proj_3x4[:, :3]
p4_3x1 = proj_3x4[:, 3]
m_inv_3x3 = np.linalg.inv(m_3x3)
# projection matrix to camera center
camera_center_3x1 = np.expand_dims(-m_inv_3x3 @ p4_3x1, 1)
camera_center_homo_4x1 = np.vstack([camera_center_3x1, 1])
# projection matrix + pixel locations to ray directions
sub_pixels_homo_3xn = convert_nx2_to_homo_3xn(sub_pixels_nx2)
ray_directions_3xn = m_inv_3x3 @ sub_pixels_homo_3xn
ray_directions_homo_4xn = convert_nx3_to_homo_4xn(ray_directions_3xn.T)
ray_directions_homo_4xn[3, :] = 0 # this is a direction
return ray_directions_homo_4xn, camera_center_homo_4x1
```
lector de matemáticas
BBSysDyn
lector de matemáticas
lector de matemáticas
BBSysDyn
amd
amd
amd
BBSysDyn
amd
amd