Почему триангулированные точки не проецируются обратно на те же точки изображения в OpenCV? - PullRequest
1 голос
/ 07 июня 2019

У меня есть две соответствующие точки изображения (2D), визуализированные одной и той же камерой с внутренней матрицей K, каждая из которых поступает из разных поз камеры (R1, t1, R2, t2). Если я триангулирую соответствующие точки изображения в трехмерную точку, а затем перепроектирую их обратно на исходные камеры, это только близко соответствует исходной точке изображения в первой камере. Может кто-нибудь помочь мне понять почему? Вот минимальный пример, показывающий проблему:

import cv2
import numpy as np

# Set up two cameras near each other

K = np.array([
    [718.856 ,   0.  ,   607.1928],
    [  0.  ,   718.856 , 185.2157],
    [  0.  ,     0.   ,    1.    ],
])

R1 = np.array([
    [1., 0., 0.],
    [0., 1., 0.],
    [0., 0., 1.]
])

R2 = np.array([
    [ 0.99999183 ,-0.00280829 ,-0.00290702],
    [ 0.0028008  , 0.99999276, -0.00257697],
    [ 0.00291424 , 0.00256881 , 0.99999245]
])

t1 = np.array([[0.], [0.], [0.]])

t2 = np.array([[-0.02182627], [ 0.00733316], [ 0.99973488]])

P1 = np.hstack([R1.T, -R1.T.dot(t1)])
P2 = np.hstack([R2.T, -R2.T.dot(t2)])

P1 = K.dot(P1)
P2 = K.dot(P2)

# Corresponding image points
imagePoint1 = np.array([371.91915894, 221.53485107])
imagePoint2 = np.array([368.26071167, 224.86262512])

# Triangulate
point3D = cv2.triangulatePoints(P1, P2, imagePoint1, imagePoint2).T
point3D = point3D[:, :3] / point3D[:, 3:4]
print(point3D)

# Reproject back into the two cameras
rvec1, _ = cv2.Rodrigues(R1)
rvec2, _ = cv2.Rodrigues(R2)

p1, _ = cv2.projectPoints(point3D, rvec1, t1, K, distCoeffs=None)
p2, _ = cv2.projectPoints(point3D, rvec2, t2, K, distCoeffs=None)

# measure difference between original image point and reporjected image point 

reprojection_error1 = np.linalg.norm(imagePoint1 - p1[0, :])
reprojection_error2 = np.linalg.norm(imagePoint2 - p2[0, :])

print(reprojection_error1, reprojection_error2)

Ошибка перепроецирования в первой камере всегда хорошая (<1px), но у второй всегда большая. </p>

1 Ответ

2 голосов
/ 08 июня 2019

Помните, как вы строите матрицу проекции с транспонированием матрицы вращения в сочетании с негативом вектора переноса. Вы должны сделать то же самое, когда помещаете это в cv2.projectPoints.

Поэтому возьмите транспонирование матрицы вращения и поместите ее в cv2.Rodrigues. Наконец, укажите отрицательный вектор перевода в cv2.projectPoints:

# Reproject back into the two cameras
rvec1, _ = cv2.Rodrigues(R1.T) # Change
rvec2, _ = cv2.Rodrigues(R2.T) # Change

p1, _ = cv2.projectPoints(point3D, rvec1, -t1, K, distCoeffs=None) # Change
p2, _ = cv2.projectPoints(point3D, rvec2, -t2, K, distCoeffs=None) # Change

Делая это, мы теперь получаем:

[[-12.19064      1.8813655   37.24711708]]
0.009565768222768252 0.08597237597736622

Чтобы быть абсолютно уверенным, вот соответствующие переменные:

In [32]: p1
Out[32]: array([[[371.91782052, 221.5253794 ]]])

In [33]: p2
Out[33]: array([[[368.3204979 , 224.92440583]]])

In [34]: imagePoint1
Out[34]: array([371.91915894, 221.53485107])

In [35]: imagePoint2
Out[35]: array([368.26071167, 224.86262512])

Мы можем видеть, что первые несколько значащих цифр совпадают, и мы ожидаем, что есть небольшая потеря в точности из-за того, что решение методом наименьших квадратов решает, куда точки триангулируют.

...