Я пытаюсь триангулировать некоторые точки с OpenCV, и я нашел это cv::triangulatePoints()
функция. Проблема в том, что там почти нет документации или примеров.
У меня есть некоторые сомнения по этому поводу.
Какой метод он использует?
Я провел небольшое исследование о триангуляции, и есть несколько методов (Линейный, Линейный LS, Собственный, итерационный LS, Итерационный Собственный, …), но я не могу найти, какой из них он использует в OpenCV.
Как я должен использовать это? Похоже, что в качестве входных данных ему нужна матрица проекции и 3XN гомогенный 2D точки. Я их определил как std::vector<cv::Point3d> pnts
, но в качестве выхода это нужно 4xN массивы и, очевидно, я не могу создать std::vector<cv::Point4d>
потому что он не существует, так как мне определить выходной вектор?
На второй вопрос я попробовал: cv::Mat pnts3D(4,N,CV_64F);
а также cv::Mat pnts3d;
, ни один из них не работает (это исключение).
1.- Метод используется наименьших квадратов. Есть более сложные алгоритмы, чем этот. Тем не менее, он является наиболее распространенным, так как другие методы в некоторых случаях могут потерпеть неудачу (то есть некоторые другие потерпят неудачу, если точки находятся на плоскости или на бесконечности).
Метод можно найти в Геометрия с несколькими видами в компьютерном зрении от Ричард Хартли и Эндрю Циссерман (P312)
2.-Использование:
cv::Mat pnts3D(1,N,CV_64FC4);
cv::Mat cam0pnts(1,N,CV_64FC2);
cv::Mat cam1pnts(1,N,CV_64FC2);
Заполните 2 точечные матрицы каналов с точками на изображениях.
cam0
а также cam1
являются Mat3x4
матрицы камеры (внутренние и внешние параметры). Вы можете построить их, умножив A * RT, где A — матрица внутренних параметров, а RT — матрица поз 3×4 с поворотом.
cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);
НОТА: pnts3D
Нужно быть 4 канала 1xN cv::Mat
если определено, выдает исключение, если нет, но результатом является cv::Mat(4,N,cv_64FC1)
матрица. Действительно сбивает с толку, но это единственный способ, которым я не получил исключение.
ОБНОВИТЬ: Начиная с версии 3.0 или, возможно, ранее, это больше не так, и pnts3D
также может быть типа Mat(4,N,CV_64FC1)
или может быть оставлен полностью пустым (как обычно, он создается внутри функции).
Небольшое дополнение к ответу Андер Бигури. Вы должны получить ваши очки изображения наundistort
редактировать изображение и вызывать undistortPoints()
на cam0pnts
а также cam1pnts
, так как cv::triangulatePoints
ожидает 2D точки в нормализованных координатах (независимо от камеры) и cam0
а также cam1
должно быть только [R | T ^ T] Матрицы вам не нужно умножать его с .
Спасибо Андеру Бигури! Его ответ мне очень помог. Но я всегда предпочитаю альтернативу с std :: vector, я отредактировал его решение так:
std::vector<cv::Point2d> cam0pnts;
std::vector<cv::Point2d> cam1pnts;
// You fill them, both with the same size...
// You can pick any of the following 2 (your choice)
// cv::Mat pnts3D(1,cam0pnts.size(),CV_64FC4);
cv::Mat pnts3D(4,cam0pnts.size(),CV_64F);
cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);
Так что вам просто нужно сделать emplace_back в точках. Основное преимущество: вам не нужно знать размер N
прежде чем начинать их заполнять. К сожалению, нет cv :: Point4f, поэтому pnts3D должен быть cv :: Mat …
Я пробовал cv :: triangulatePoints, но каким-то образом он вычисляет мусор. Я был вынужден вручную реализовать метод линейной триангуляции, который возвращает матрицу 4×1 для триангулированной трехмерной точки:
Mat triangulate_Linear_LS(Mat mat_P_l, Mat mat_P_r, Mat warped_back_l, Mat warped_back_r)
{
Mat A(4,3,CV_64FC1), b(4,1,CV_64FC1), X(3,1,CV_64FC1), X_homogeneous(4,1,CV_64FC1), W(1,1,CV_64FC1);
W.at<double>(0,0) = 1.0;
A.at<double>(0,0) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,0) - mat_P_l.at<double>(0,0);
A.at<double>(0,1) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,1) - mat_P_l.at<double>(0,1);
A.at<double>(0,2) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,2) - mat_P_l.at<double>(0,2);
A.at<double>(1,0) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,0) - mat_P_l.at<double>(1,0);
A.at<double>(1,1) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,1) - mat_P_l.at<double>(1,1);
A.at<double>(1,2) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,2) - mat_P_l.at<double>(1,2);
A.at<double>(2,0) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,0) - mat_P_r.at<double>(0,0);
A.at<double>(2,1) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,1) - mat_P_r.at<double>(0,1);
A.at<double>(2,2) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,2) - mat_P_r.at<double>(0,2);
A.at<double>(3,0) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,0) - mat_P_r.at<double>(1,0);
A.at<double>(3,1) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,1) - mat_P_r.at<double>(1,1);
A.at<double>(3,2) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,2) - mat_P_r.at<double>(1,2);
b.at<double>(0,0) = -((warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,3) - mat_P_l.at<double>(0,3));
b.at<double>(1,0) = -((warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,3) - mat_P_l.at<double>(1,3));
b.at<double>(2,0) = -((warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,3) - mat_P_r.at<double>(0,3));
b.at<double>(3,0) = -((warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,3) - mat_P_r.at<double>(1,3));
solve(A,b,X,DECOMP_SVD);
vconcat(X,W,X_homogeneous);
return X_homogeneous;
}
входными параметрами являются две матрицы проекции камеры 3×4 и соответствующая пара левого / правого пикселей (x, y, w).
В качестве альтернативы вы могли бы использовать метод от Хартли & Зиссерман реализовал здесь: http://www.morethantechnical.com/2012/01/04/simple-triangulation-with-opencv-from-harley-zisserman-w-code/