Mon point de vue mathématique est-il correct?

24

J'ai des devoirs dans lesquels je dois calculer et tracer certains points à l'aide d'une transformation en perspective, mais je ne suis pas sûr que mes résultats soient corrects, car le tracé 3D utilisant les coordonnées de la caméra est très différent du tracé 2D utilisant les coordonnées de l'image . Pouvez-vous m'aider à comprendre ce qui ne va pas?

Voici ce qui est donné: La caméra est au point , spécifié en coordonnées mondiales (en mètres). Le système de coordonnées de la caméra tourne autour de l'axe Y de la référence mondiale de , donc sa matrice de rotation est θ = 160 o w R c = [ c o s ( θ ) 0 s i n ( θ ) 0 1 0 - s i n ( θ ) 0 c o s ( θ ) ]WTC=[-1,1,5]Tθ=160owRc=[cos(θ)0sjen(θ)010-sjen(θ)0cos(θ)]

Les paramètres de l'appareil photo sont: , , ,s x = s y = 0,01 m m / p x o x = 320 p x o y = 240 p xF=16mmsX=sy=0,01mm/pXoX=320pXoy=240pX

Exemples de points (en coordonnées mondiales):

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

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

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

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

Je dois calculer et tracer les points en coordonnées de caméra et en coordonnées d'image, j'ai donc écrit le code suivant dans 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()

Et ce sont les intrigues que j'ai du script: je m'attendais à ce qu'elles soient quelque peu similaires, mais elles ne le semblent pas.

Tracé 3D

Tracer les coordonnées de la caméra

Tracé 2D

Tracer en coordonnées d'image

Vitor
la source
8
+1 pour montrer que les questions de devoirs peuvent être des questions de haute qualité. :)
Martin Ender
2
Comme indiqué sur la méta, cette question mérite une bonne réponse. Je n'en ai pas moi-même, mais je suis heureux de donner une partie de ma réputation à quelqu'un qui en a.
trichoplax
@trichoplax le problème est que c'est fait dans matlab.
joojaa
@joojaa ah bon point. Si aucun expert de matlab n'intervient pendant la période de prime, j'envisagerai d'apprendre Octave pour voir si c'est assez proche pour trouver une solution.
trichoplax
1
Ce n'est pas très clair pour moi ce que la première image est censée signifier. La seconde est du point de vue de la caméra, et après un retour d'estimation de l'enveloppe, je pense qu'elle semble correcte.
Julien Guertault

Réponses:

8

Identifier vos axes dans les deux figures et ajouter la position de la caméra à votre première figure vous aiderait à comprendre ce qui se passe.

Xyz

[0,0,1][0,1,0]

0,016SX=Sy=0,00010,00001

[-1,1,X]z=0,5Xtunen(160°)(5-0,5)=1,64 ...X=-10,64ycoordonnées que deux points, et que les coordonnées ne sont pas modifiées par la rotation, ils devraient encore se retrouver sur les mêmes coordonnées après la transformation, ce qui signifie sur la ligne centrale de l'image.y

Un bon moyen de vérifier votre réponse consiste à utiliser un modeleur 3D existant comme Blender: Scène 3D dans Blender soyez prudent avec le système de coordonnées de Blender, par exemple le vecteur de caméra par défaut est [0, 0, -1]. Voici le rendu: Rendu dans Blender Focal a été défini sur une autre valeur pour rendre la sphère plus visible. Nous voyons donc que les deux points inférieurs sont sur la ligne du milieu de l'image et les points sont légèrement à droite de l'image.

J'ai implémenté vos devoirs 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()

Cela me donne ces chiffres: respectivement: coordonnées du monde, coordonnées de la caméra, coordonnées de la caméra pivotées pour s'adapter légèrement à l'orientation de la caméra (notez qu'ici le vecteur de la caméra va vers le point de vue de la figure, il n'entre pas "la figure") et les coordonnées de l'image.Coordonnées mondiales Coordonnées de la caméra Coordonnées de la caméra pivotées Coordonnées de l'image

Nous voyons donc que les coordonnées verticales pour les points inférieurs sont correctement sur la ligne du milieu (240) et les points sont sur le côté droit de l'image (valeur horizontale> 320).

Je crois qu'un bug que vous avez eu est que vous avez trouvé des valeurs X négatives, donc vous avez annulé les focales ( -f/Sxy) dans la matrice intrinsèque pour compenser. Le problème ici est que nous avons supposé que la caméra pointait initialement vers (sinon la rotation de 160 ° ne pointerait pas vers les points). Si vous le regardez de cette façon, l' axe des augmente lorsque vous vous dirigez vers la gauche , l'inverse de cet axe doit être pris.[0,0,1]X

[0,-1,0]

Soravux
la source