Ответ 1
Я столкнулся с той же проблемой, что и вы, в OpenCV. У меня была пара стереоизображений, и я хотел вычислить внешние параметры камер и мировые координаты всех наблюдаемых точек. Эта проблема была рассмотрена здесь:
Бертольд К. П. Хорн. Относительная ориентация пересмотрена. Бертольд К. П. Хорн. Лаборатория искусственного интеллекта, Массачусетский технологический институт, технология 545...
http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.64.4700
Однако я не смог найти подходящую реализацию этой проблемы (возможно, вы ее найдете). Из-за ограничений по времени у меня не было времени понять все математики в этой статье и реализовать ее самостоятельно, поэтому я придумал быстрое и грязное решение, которое работает для меня. Я объясню, что я сделал, чтобы решить эту проблему:
Предполагая, что у нас есть две камеры, где первая камера имеет внешние параметры RT = Matx:: eye(). Теперь сделайте предположение о вращении R второй камеры. Для каждой пары точек изображения, наблюдаемых на обоих изображениях, мы вычисляем направления их соответствующих лучей в мировых координатах и сохраняем их в 2d-массиве dirs (EDIT: предполагается, что параметры внутренней камеры известны). Мы можем это сделать, поскольку мы предполагаем, что мы знаем ориентацию каждой камеры. Теперь мы построим переопределенную линейную систему AC = 0, где C - центр второй камеры. Я предоставляю вам функцию для вычисления A:
Mat buildA(Matx<double, 3, 3> &R, Array<Vec3d, 2> dirs)
{
CV_Assert(dirs.size(0) == 2);
int pointCount = dirs.size(1);
Mat A(pointCount, 3, DataType<double>::type);
Vec3d *a = (Vec3d *)A.data;
for (int i = 0; i < pointCount; i++)
{
a[i] = dirs(0, i).cross(toVec(R*dirs(1, i)));
double length = norm(a[i]);
if (length == 0.0)
{
CV_Assert(false);
}
else
{
a[i] *= (1.0/length);
}
}
return A;
}
Тогда вызов cv:: SVD:: solveZ (A) даст вам решение этой нормы с наименьшими квадратами. Таким образом, вы получаете поворот и перевод второй камеры. Однако, поскольку я только что сделал предположение о вращении второй камеры, я делаю несколько догадок о ее вращении (параметризованный с использованием омега вектора 3x1, из которого я вычисляю матрицу вращения с использованием cv:: Rodrigues), а затем уточню это предположение решая систему AC = 0 повторно в оптимизаторе Левенберга-Марквардта с числовым якобием. Это работает для меня, но это немного грязно, поэтому, если у вас есть время, я рекомендую вам реализовать то, что объяснено в статье.
EDIT:
Вот рутина в оптимизаторе Левенберга-Марквардта для оценки вектора вычетов:
void Stereo::eval(Mat &X, Mat &residues, Mat &weights)
{
Matx<double, 3, 3> R2Ref = getRot(X); // Map the 3x1 euler angle to a rotation matrix
Mat A = buildA(R2Ref, _dirs); // Compute the A matrix that measures the distance between ray pairs
Vec3d c;
Mat cMat(c, false);
SVD::solveZ(A, cMat); // Find the optimum camera centre of the second camera at distance 1 from the first camera
residues = A*cMat; // Compute the output vector whose length we are minimizing
weights.setTo(1.0);
}
Кстати, я несколько раз искал в Интернете и нашел другой код, который может быть полезен для вычисления относительной ориентации между камерами. Я еще не пробовал код, но он кажется полезным:
http://www9.in.tum.de/praktika/ppbv.WS02/doc/html/reference/cpp/toc_tools_stereo.html