Подтвердить что ты не робот

Как правильно использовать cv:: triangulatePoints()

Я пытаюсь triangulate некоторые точки с 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;, ни один из них не работает (он выдает исключение).

4b9b3361

Ответ 1

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 - матрица переноса поворота 3x4.

cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);

ПРИМЕЧАНИЕ: pnts3D НУЖДЫ должны быть 4-канальным 1xN cv::Mat, если определено, генерирует исключение, если нет, но результатом является матрица cv::Mat(4,N,cv_64FC1). На самом деле сбивает с толку, но это единственный способ, которым я не получал исключения.


UPDATE. Начиная с версии 3.0 или, возможно, раньше, это больше не верно, а pnts3D также может иметь тип Mat(4,N,CV_64FC1) или может быть оставлено полностью пустым (как обычно, это созданный внутри функции).

Ответ 2

Небольшое дополнение к ответу @Ander Biguri. Вы должны получить свои точки изображения на изображении без undistort и вызвать undistortPoints() на cam0pnts и cam1pnts, потому что cv::triangulatePoints ожидает двумерные точки в нормализованных координатах (независимо от камеры) и cam0 и cam1 должны быть только [R | t ^ T], вам не нужно многократно с A.

Ответ 3

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

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;
}

входными параметрами являются две матрицы проецирования камеры 3x4 и соответствующая пара правых/правых пикселей (x, y, w).

Ответ 4

Спасибо Андер Бигури! Его ответ очень помог мне. Но я всегда предпочитаю альтернативу с 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...