A matemática da minha perspectiva está correta?

24

Tenho uma lição de casa na qual tenho que calcular e plotar alguns pontos usando uma transformação em perspectiva, mas não tenho certeza de que meus resultados estejam corretos, pois o gráfico 3D usando coordenadas de câmera parece muito diferente do gráfico 2D usando as coordenadas da imagem . Você pode me ajudar a entender o que há de errado?

É o seguinte: A câmera está no ponto W T C = [ - 1 , 1 , 5 ] T , especificado nas coordenadas do mundo (em metros). A câmara do sistema de coordenadas é girado em torno do eixo Y da referência mundo por θ = 160 o , por isso, de matriz de rotação é w R c = [ c o s ( θ ) 0 s i n ( θ ) 0 1 0 - s i n (WTC=[-1 1,1 1,5]Tθ=160oWRc=[cos(θ)0 0sEun(θ)0 01 10 0-sEun(θ)0 0cos(θ)]

Câmara parâmetro são as seguintes: f=16mm , sx=sy=0,01mm/px , ox=320px , oy=240px

Pontos de amostra (em coordenadas mundiais):

WP1 1=[1 1,1 1,0,5]T

WP2=[1 1,1.5,0,5]T

WP3=[1.5,1.5,0,5]T

WP4=[1.5,1 1,0,5]T

Eu tenho que calcular e plotar os pontos nas coordenadas da câmera e nas coordenadas da imagem, então escrevi o seguinte código no 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()

E estas são as tramas que recebi do roteiro: esperava que elas fossem um pouco parecidas, mas não parecem.

Gráfico 3D

Plotar coordenadas da câmera

Plotagem 2D

Plotar nas coordenadas da imagem

Vitor
fonte
8
+1 por mostrar que as perguntas dos trabalhos de casa podem ser de alta qualidade. :)
Martin Ender
2
Como apontado na meta, esta pergunta merece uma boa resposta. Eu não tenho um, mas estou feliz em dar um pouco da minha reputação a alguém que o possui.
Trichoplax
@trichoplax o problema é que isso é feito no matlab.
Joojaa 01/09/16
@joojaa ah bom ponto. Se nenhum especialista em matlab intervir durante o período de recompensa, considerarei aprender o Octave para ver se está próximo o suficiente para encontrar uma solução.
Trichoplax
11
Não está muito claro para mim o que a primeira imagem deve significar. O segundo é do ponto de vista da câmera e, depois de uma estimativa do verso do envelope, acho que parece correto.
Julien Guertault

Respostas:

8

Identificar seus eixos nas duas figuras e adicionar a posição da câmera à sua primeira figura ajudará você a entender o que está acontecendo.

xyz . Dessa forma, você pode lidar com a projeção usando uma multiplicação simples da matriz em vez de manipular cada linha separadamente.

[0 0,0 0,1 1][0 0,1 1,0 0] . Se alguma dessas suposições estiver errada, o restante da resposta estará errado.

0,016Sx=Sy=0,00010,00001

[-1 1,1 1,x]z=0,5xtuman(160°)(5-0,5)=1,64 ...x=-1 10,64yy

Uma boa maneira de verificar sua resposta é usando um modelador 3D existente como o Blender: Cena 3D no Blender tenha cuidado com o sistema de coordenadas do Blender, por exemplo, o vetor padrão da câmera é [0, 0, -1]. Aqui está a renderização: Renderizar no Blender Focal foi definido com outro valor para tornar a esfera mais visível. Portanto, vemos que os dois pontos inferiores estão na linha do meio da imagem e os pontos estão ligeiramente à direita da imagem.

Eu implementei sua lição de casa em 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()

Isso me dá as seguintes figuras: Respectivamente: coordenadas mundiais, coordenadas da câmera, coordenadas da câmera giradas para se ajustar levemente à orientação da câmera (observe que aqui o vetor da câmera vai em direção ao ponto de vista da figura, ele não "entra" na figura) e nas coordenadas da imagem.Coordenadas mundiais Coordenadas da câmera Coordenadas da câmera giradas Coordenadas da imagem

Portanto, vemos que as coordenadas verticais para os pontos inferiores estão corretamente na linha do meio (240) e os pontos estão no lado direito da imagem (valor horizontal> 320).

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

[0 0,-1 1,0 0]

Soravux
fonte