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

Вычисление координаты x, y (3D) из точки изображения

У меня есть задача найти объект в 3D-системе координат. Поскольку мне нужно получить почти точную координату X и Y, я решил отслеживать один цветной маркер с известной координатой Z, который будет размещен на верхней части движущегося объекта, например, оранжевый шар на этом изображении: undistored

Во-первых, я выполнил калибровку камеры, чтобы получить внутренние параметры, и после этого я использовал cv:: solvePnP для получения вектора вращения и перевода, как в этом следующем коде:

std::vector<cv::Point2f> imagePoints;
std::vector<cv::Point3f> objectPoints;
//img points are green dots in the picture
imagePoints.push_back(cv::Point2f(271.,109.));
imagePoints.push_back(cv::Point2f(65.,208.));
imagePoints.push_back(cv::Point2f(334.,459.));
imagePoints.push_back(cv::Point2f(600.,225.));

//object points are measured in millimeters because calibration is done in mm also
objectPoints.push_back(cv::Point3f(0., 0., 0.));
objectPoints.push_back(cv::Point3f(-511.,2181.,0.));
objectPoints.push_back(cv::Point3f(-3574.,2354.,0.));
objectPoints.push_back(cv::Point3f(-3400.,0.,0.));

cv::Mat rvec(1,3,cv::DataType<double>::type);
cv::Mat tvec(1,3,cv::DataType<double>::type);
cv::Mat rotationMatrix(3,3,cv::DataType<double>::type);

cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec);
cv::Rodrigues(rvec,rotationMatrix);

После наличия всех матриц это уравнение, которое может помочь мне преобразовать точку изображения в wolrd координаты:

transform_equation

где M является CameraMatrix, R - rotationMatrix, t - tvec и s неизвестно. Zconst представляет собой высоту, где находится оранжевый шар, в этом примере это 285 мм. Итак, сначала мне нужно решить предыдущее уравнение, получить "s", и после того, как я смогу найти координаты X и Y, выбрав точку изображения: equation2

Решая это, я могу узнать переменную "s", используя последнюю строку в матрицах, потому что Zconst известен, так что вот для этого следующий код:

cv::Mat uvPoint = cv::Mat::ones(3,1,cv::DataType<double>::type); //u,v,1
uvPoint.at<double>(0,0) = 363.; //got this point using mouse callback
uvPoint.at<double>(1,0) = 222.;
cv::Mat tempMat, tempMat2;
double s;
tempMat = rotationMatrix.inv() * cameraMatrix.inv() * uvPoint;
tempMat2 = rotationMatrix.inv() * tvec;
s = 285 + tempMat2.at<double>(2,0); //285 represents the height Zconst
s /= tempMat.at<double>(2,0);
std::cout << "P = " << rotationMatrix.inv() * (s * cameraMatrix.inv() * uvPoint - tvec) << std::endl;

После этого я получил результат: P = [-2629.5, 1272.6, 285.]

и когда я сравниваю его с измерением: Preal = [-2629.6, 1269.5, 285.]

ошибка очень маленькая, что очень хорошо, но когда я перемещаю этот ящик по краям этой комнаты, ошибки могут составлять 20-40 мм, и я хотел бы улучшить это. Может ли кто-нибудь помочь мне в этом, есть ли у вас какие-либо предложения?

4b9b3361

Ответ 1

Учитывая вашу конфигурацию, ошибки в 20-40 мм по краям являются средними. Похоже, вы все сделали хорошо.

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

Как указано count0, если вам нужна более высокая точность, вы должны пойти на несколько измерений.

Ответ 2

Получаете ли вы зеленые точки (изображения) из искаженного или неискаженного изображения? Поскольку функция solvePnP уже не соответствует показаниям изображений (если вы не передадите коэффициенты искажения или не передадите их как null). Если вы получаете их от неискаженного изображения, вы можете искажать эти изображения в два раза, и это приведет к увеличению ошибки в углах.

https://github.com/Itseez/opencv/blob/master/modules/calib3d/src/solvepnp.cpp