У меня есть камера для рыбного глаза в потолке, и я хочу найти некоторые точки на полу. Я поставил источник моей системы ссылок (реальный мир) чуть ниже камеры, и я хочу знать положение каждого объекта в сантиметрах. Эта фотография показывает, что это:Точки изображения (в пикселях) до координат реального мира (метров)
Во-первых, я сделал калибровку камеры и я получил следующий результат с RMS 1,11:
Undistorted image after calibration
В результате калибровки Я получил собственные параметры (матрица камеры), поэтому я использовал cv :: solvePnP для получения векторов вращения и трансляции. Для этого я отметил некоторые моменты неискаженного изображения (в пикселях), и я измерил их в реальном мире в соответствии с моей системой отсчета.
Например, происхождение находится в центре 1024x768 изображения, так что:
- Точка 0: ImagePoint (512, 384) [пикселей] -> ObjectPoint (0,0) [см]
следующий код показывает это:
std::vector<cv::Point2f> imagePointsPix;
std::vector<cv::Point3f> objectPointsCm;
imagePointsPix.push_back(cv::Point2f(512.,384.));
imagePointsPix.push_back(cv::Point2f(404.,512.));
imagePointsPix.push_back(cv::Point2f(666.,211.));
imagePointsPix.push_back(cv::Point2f(519.,66.));
objectPointsCm.push_back(cv::Point3f(0., 0., 0.));
objectPointsCm.push_back(cv::Point3f(-80.,-132.,0.));
objectPointsCm.push_back(cv::Point3f(120.,188.,0.));
objectPointsCm.push_back(cv::Point3f(-40.,268.,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(objectPointsCm, imagePointsPix, cameraMatrix, distCoeffs, rvec, tvec, 0, SOLVEPNP_ITERATIVE);
cv::Rodrigues(rvec,rotationMatrix);
Теперь у меня есть матрица камеры, матрицы вращения и вектор traslation, поэтому при использовании this в качестве ссылки Я могу вычислить любую точку, если у меня есть ее позиция в пикселях. Это код:
cv::Mat uvPoint = cv::Mat::ones(3,1,cv::DataType<double>::type); //u,v,1
uvPoint.at<double>(0,0) = 512.; //img point for which we want its real coordinates
uvPoint.at<double>(1,0) = 384.;
cv::Mat tempMat, tempMat2;
double s;
tempMat = rotationMatrix.inv() * cameraMatrix.inv() * uvPoint;
tempMat2 = rotationMatrix.inv() * tvec;
s = 0 + tempMat2.at<double>(2,0); //before 0 it was 285, which represents the height Zconst
s /= tempMat.at<double>(2,0);
std::cout << "P = " << rotationMatrix.inv() * (s * cameraMatrix.inv() * uvPoint - tvec) << std::endl;
Я получаю это результаты для же точек я использовал для получения своих параметров:
- точки 0 -> (0,213, 3,391) (оно должно быть (0,0)) ОШИБКА: 3,69 см
- Точка 1 -> (-68,28, -112.82) (он должен быть (-80, -132)) ОШИБКА: 17.49 см
- Точка 2 - -> (84,4 8, 137,61) (это должно быть (120, 188)) ОШИБКА: 49,62 см
Остальные точек также показывают ошибку слишком большой ... Я использовал больше очков, но результаты не улучшаются , Я не знаю, где я ошибся, может ли кто-нибудь мне помочь?
Заранее благодарен.
Есть вероятность, что калибровка будет прекрасной, и что вы эффективно искажаете изображение дважды (см. Мой ответ для объяснения). – rob3c