Оценить ориентацию камеры по наземным 3D-точкам?

#opencv #vision #depth-camera

#opencv #миссия #глубина-камера

Вопрос:

Учитывая набор 3D-точек в перспективе камеры, соответствующих плоской поверхности (земле), существует ли какой-либо быстрый эффективный метод определения ориентации плоскости относительно плоскости камеры? Или это возможно только при использовании более сложных алгоритмов «сопоставления поверхностей» в облаке точек?

Я пытался использовать estimateAffine3D и findHomography , но мое главное ограничение заключается в том, что у меня нет координат точек на плоскости поверхности — я могу выбрать только набор точек из глубинных изображений и, следовательно, должен работать с набором 3D-точек в кадре камеры. ,

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

РЕДАКТИРОВАТЬ: следуя предложению @Micka, я попытался подогнать точки к 2D-плоскости на кадре камеры со следующей функцией:

 #include <opencv2/opencv.hpp>

//------------------------------------------------------------------------------
/// @brief      Fits a set of 3D points to a 2D plane, by solving a system of linear equations of type aX   bY   cZ   d = 0
///
/// @param[in]  points             The points
///
/// @return     4x1 Mat with plane equations coefficients [a, b, c, d]
///
cv::Mat fitPlane(const std::vector< cv::Point3d >amp; points) {
    // plane equation: aX   bY   cZ   d = 0
    // assuming c=-1 ->  aX   bY   d = z

    cv::Mat xys = cv::Mat::ones(points.size(), 3, CV_64FC1);
    cv::Mat zs  = cv::Mat::ones(points.size(), 1, CV_64FC1);

    // populate left and right hand matrices
    for (int idx = 0; idx < points.size(); idx  ) {
        xys.at< double >(idx, 0) = points[idx].x;
        xys.at< double >(idx, 1) = points[idx].y;
        zs.at< double >(idx, 0)  = points[idx].z;
    }

    // coeff mat
    cv::Mat coeff(3, 1, CV_64FC1);

    // problem is now xys * coeff = zs
    // solving using SVD should output coeff
    cv::SVD svd(xys);
    svd.backSubst(zs, coeff);

    // alternative approach -> requires mat with 3D coordinates amp; additional col
    // solves xyzs * coeff = 0
    // cv::SVD::solveZ(xyzs, coeff);  // @note: data type must be double (CV_64FC1)

    // check result w/ input coordinates (plane equation should output null or very small values)
    double a = coeff.at< double >(0);
    double b = coeff.at< double >(1);
    double d = coeff.at< double >(2);
    for (autoamp; point : points) {
        std::cout << a * point.x   b * point.y   d - point.z << std::endl;
    }

    return coeff;

}
 

В целях простоты предполагается, что камера правильно откалибрована и что 3D-реконструкция правильная — что я уже проверял ранее и, следовательно, выходит за рамки этой проблемы. Я использую мышь, чтобы выбрать точки в паре глубина / цвет кадра, восстановить 3D-координаты и передать их в функцию выше.

Я также пробовал другие подходы cv::SVD::solveZ() , такие как инвертирование xyz с cv::invert() помощью и с cv::solve() помощью, но это всегда заканчивалось либо смехотворно малыми значениями, либо ошибками во время выполнения, касающимися размера и / или типа матрицы.

Комментарии:

1. итак, вы знаете плоские точки на вашем изображении глубины? Подгонка плоскости к ним должна быть простой?

2. Модуль calib3d OpenCV имеет несколько методов «декомпозиции» (decomposeHomographyMat). это может сработать, но проблема может быть недостаточно ограничена.

3. @Micka хотя я мог бы попытаться найти коэффициенты уравнения плоскости, не совсем ясно, как я мог бы получить из него матрицу преобразования.

4. @ChristophRackwitz матрица гомографии — это (я полагаю) то, что я ищу.

5. пожалуйста, покажите примеры того, как вы использовали solvePnP, и предоставьте информацию о том, как вы рассчитали калибровку камеры и т. Д.