opencv - 从图像点计算 x,y 坐标 (3D)

标签 opencv camera-calibration pose-estimation

我的任务是在 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);

在拥有所有矩阵之后,这个方程可以帮助我将图像点转换为世界坐标:

transform_equation

其中 M 是 cameraMatrix,R - rotationMatrix,t - tvec,s 是未知数。 Zconst 表示橙色球所在的高度,在本例中为 285 mm。 所以,首先我需要解前面的方程,得到“s”,然后我可以通过选择图像点找出 X 和 Y 坐标: equation2

解决这个问题我可以找到变量“s”,使用矩阵的最后一行,因为 Zconst 是已知的,所以这里是下面的代码:

cv::Mat uvPoint = (cv::Mat_<double>(3,1) << 363, 222, 1); // u = 363, v = 222, got this point using mouse callback

cv::Mat leftSideMat  = rotationMatrix.inv() * cameraMatrix.inv() * uvPoint;
cv::Mat rightSideMat = rotationMatrix.inv() * tvec;

double s = (285 + rightSideMat.at<double>(2,0))/leftSideMat.at<double>(2,0)); 
//285 represents the height Zconst

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 毫米,我想改进一下。谁能帮我解决这个问题,你有什么建议吗?

最佳答案

鉴于您的配置,边缘处 20-40 毫米的误差是平均水平。看起来你已经做好了一切。

如果不修改相机/系统配置,就很难做得更好。您可以尝试重做相机校准并希望获得更好的结果,但这不会改善它们很多(并且您最终可能会得到更差的结果,所以不要删除实际的内部参数)

正如 count0 所说,如果您需要更高的精度,您应该进行多次测量。

关于opencv - 从图像点计算 x,y 坐标 (3D),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12299870/

相关文章:

python - 使用边缘检测和 scikit-image 在 Python 中去除背景/屏蔽

python - 将纬度、经度和高度转换为平面 3D 空间中的点

python - 仅径向变形即可校准摄像机

c++ - solvePnpRansac GPU断言失败

multithreading - 非法内存访问 : multi-thread with one GPU ( OpenCV3. 1 + CUDA 8.0)(完整代码)

java - 如何在 Java 中过滤 OpenCV 错误消息

visual-c++ - 获取图像的像素值

matlab - Camera Calibration Intrinsic Matrix 值代表什么?

python - 对极几何姿态估计 : Epipolar lines look good but wrong pose

python - 点是否在多边形内部?方法有问题