Движение камеры с соответствующих изображений

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

На самом деле, я не получаю полезных результатов, поэтому я пытаюсь описать свою процедуру и надеюсь, что кто-то может мне помочь.

Я сопоставляю функции соответствующих изображений с SIFT, сопоставляю их с OpenCV FlannBasedMatcher и вычисляю основную матрицу с помощью OpenCV findFundamentalMat (метод RANSAC).

Затем я вычисляю существенную матрицу с помощью встроенной матрицы (K) камеры:

Mat E = K.t() * F * K;

Я разлагаю существенную матрицу на поворот и перевод с сингулярным разложением:

SVD decomp = SVD(E);
Matx33d W(0,-1,0,
          1,0,0,
          0,0,1);
Matx33d Wt(0,1,0,
          -1,0,0,
           0,0,1);
R1 = decomp.u * Mat(W) * decomp.vt;
R2 = decomp.u * Mat(Wt) * decomp.vt;
t1 = decomp.u.col(2); //u3
t2 = -decomp.u.col(2); //u3

Затем я пытаюсь найти правильное решение путем триангуляции. (эта часть от http://www.morethantechnical.com/2012/01/04/simple-triangulation-with-opencv-from-harley-zisserman-w-code/, поэтому я думаю, что это должно работать правильно).

Затем новая позиция вычисляется с помощью:

new_pos = old_pos + -R.t()*t;

где new_pos и old_pos - векторы (3x1), R - матрица поворота (3x3) и t - вектор трансляции (3x1).

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

Вот некоторые результаты (на всякий случай кто-то может подтвердить, что любой из них определенно неверен):

F = [8.093827077399547e-07, 1.102681999632987e-06, -0.0007939604310854831;
     1.29246107737264e-06, 1.492629957878578e-06, -0.001211264339006535;
     -0.001052930954975217, -0.001278667878010564, 1]

K = [150, 0, 300;
    0, 150, 400;
    0, 0, 1]

E = [0.01821111092414898, 0.02481034499174221, -0.01651092283654529;
     0.02908037424088439, 0.03358417405226801, -0.03397110489649674;
     -0.04396975675562629, -0.05262169424538553, 0.04904210357279387]

t = [0.2970648246214448; 0.7352053067682792; 0.6092828956013705]

R = [0.2048034356172475, 0.4709818957303019, -0.858039396912323;
     -0.8690270040802598, -0.3158728880490416, -0.3808101689488421;
     -0.4503860776474556, 0.8236506374002566, 0.3446041331317597]

Ответ 1

Прежде всего, вы должны проверить,

x' * F * x = 0

для ваших точечных соответствий x' и x. Это должно быть, конечно, только для случаев фундаментальной оценки матрицы с помощью RANSAC.

После этого вам необходимо преобразовать ваши соответствия точек в нормализованные координаты изображения (NCC), подобные этому

xn = inv(K) * x
xn' = inv(K') * x'

где K' - внутренняя матрица камеры второго изображения, а x' - точки второго изображения. Я думаю, что в вашем случае это K = K'.

С помощью этих NCC вы можете разложить свою основную матрицу, как вы описали. Вы триангулируете нормализованные координаты камеры и проверяете глубину ваших триангулированных точек. Но будьте осторожны, в литературе говорят, что одного пункта достаточно, чтобы получить правильное вращение и перевод. По моему опыту вы должны проверить несколько точек, поскольку одна точка может быть выбросом даже после RANSAC.

Прежде чем разложить основную матрицу, убедитесь, что E=U*diag(1,1,0)*Vt. Это условие требуется для получения правильных результатов для четырех возможных вариантов проекционной матрицы.

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

xp = K * P * X
xp' = K' * P' * X

где x - вычисленная (однородная) трехмерная позиция. P и P' являются матрицами проецирования 3x4. Проекционная матрица P обычно задается тождеством. P' = [R, t] задается матрицей вращения в первых трех столбцах и строках и переводом в четвертом столбце, так что P является матрицей 3x4. Это работает, только если вы преобразуете свое трехмерное положение в однородные координаты, то есть 4x1 векторы вместо 3x1. Тогда xp и xp' также являются однородными координатами, представляющими ваши (перепроектированные) двумерные позиции ваших соответствующих точек.

Я думаю, что

new_pos = old_pos + -R.t()*t;

неверно, так как во-первых, вы только переводите old_pos, и вы не поворачиваете его, а во-вторых, вы переводите его с неправильным вектором. Правильный путь приведен выше.

Итак, после вычисления перепрограммированных точек вы можете вычислить ошибку повторения. Поскольку вы работаете с однородными координатами, вы должны их нормализовать (xp = xp / xp(2), делить на последнюю координату). Это дается

error = (x(0)-xp(0))^2 + (x(1)-xp(1))^2

Если ошибка велика, например 10 ^ 2, ваша собственная калибровка камеры или ваш поворот/перевод неверны (возможно, оба). В зависимости от вашей системы координат вы можете попытаться инвертировать проекционные матрицы. В этом случае вам нужно преобразовать их в однородные координаты до того, как вы не сможете инвертировать матрицу 3x4 (без псевдоверса). Таким образом, добавьте четвертую строку [0 0 0 1], вычислите обратную и удалите четвертую строку.

Есть еще одна вещь с ошибкой перепечатки. В общем случае ошибка повторного воспроизведения представляет собой квадрат расстояния между вашим исходным соответствием точки (на каждом изображении) и перепрограммированной позицией. Вы можете взять квадратный корень, чтобы получить евклидовое расстояние между обеими точками.

Ответ 2

Чтобы обновить положение камеры, вам сначала необходимо обновить перевод, а затем обновить матрицу вращения.

t_ref += lambda * (R_ref * t);
R_ref = R * R_ref;

где t_ref и R_ref - состояние вашей камеры, R и t - это новое вычисление вращения и трансляции камеры, а лямбда - масштабный коэффициент.