图像点(像素)到真实世界坐标(米)

时间:2016-06-08 15:32:34

标签: c++ opencv camera-calibration pose-estimation

天花板上有一个鱼眼相机,我想在地板上找到一些点。我已将我的参考系统(真实世界)的原点放在相机下方,我想知道每个物体的位置,以厘米为单位。这张照片显示了这个:

Reference system - Real world

首先,我完成了相机校准,并获得了下一个结果,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);

现在我有了相机矩阵,旋转矩阵和相关矢量,因此通过使用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 - &gt; (0.213,3.391)(应为(0,0))错误:3.69 cm
  • 第1点 - &gt; (-68.28,-112.82)(应该是(-80,-132))错误:17.49厘米
  • 第2点 - &gt; (84.48,137.61)(应为(120,188))错误:49.62 cm

其余的点也显示错误太大......我使用了更多的积分,但结果没有改善。我不知道哪里出错了,有人可以帮助我吗?

提前致谢。

2 个答案:

答案 0 :(得分:1)

solvePNP的角度看,你可能会有效地对你的图像进行两次失真。这是因为传递了失真系数以及已经从未失真图像导出的点对应关系。

尝试将校准中的实际相机矩阵传递给solvePNP而不是单位矩阵,但仍然会为失真系数传递NULL,以避免双重失真。

答案 1 :(得分:0)

最后我发现错误是由失真系数引起的,即我的校准。我将cameraMatrix设置为Identity矩阵(eye(3))并将distCoefficients设置为NULL,以便solvePNP假设我有一个完美的相机。使用这种方法我得到的误差要低得多。我将不得不做出更好的校准。