#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, и предоставьте информацию о том, как вы рассчитали калибровку камеры и т. Д.