从OpenCV的SolvPnP函数中获取正确的rvec和tvec以进行相机姿态估计

3

我正在尝试测量相机的姿态,并已完成以下操作。

  1. 在平面表面的正方形角落上标记世界三维点(假设z=0,因为它是平的),并假定一个世界坐标系。(以厘米为单位)

已将正方形的左上角作为原点,并按以下顺序(x,y)或(col,row)给出了世界点: (0,0),(-12.8,0),(-12.8,12.8),(0,12.8) - 以厘米为单位

2. 检测我的图像中的点(以像素为单位)。 图像点和世界点按相同顺序排列。 3. 我已经校准了相机的内部矩阵和畸变系数。 4. 我使用SolvePnP函数获取rvec和tvec。 5. 我使用Rodrigues函数获取旋转矩阵。 6. 为了检查rvec和tvec是否正确,我使用ProjectPoints将三维点(z=0)投影回图像平面,我在我的图像上正确地获得了点,X轴误差为3个像素。 7. 现在,我使用公式计算相机在世界坐标系中的位置: cam_worl_pos = -inverse(R) * tvec。 (我在许多博客中验证了这个公式,也很有道理) 8. 但是我的cam_worl_pos x、y和z在厘米上似乎不正确。
我的疑惑是,如果我能够使用rvec和tvec将3D世界点投影回图像平面(X轴上有3个像素的误差,Y轴上几乎没有误差,希望不会太糟),那么为什么我没有得到正确的相机位置。

此外,我对SolvPnP rvec和tvec解决方案有疑问,它们可能是多个解决方案之一,但不是我想要的。

如何从SolvPnp获取正确的rvec和tvec,或者任何其他获得rvec和tvec的建议也将有所帮助。

编辑

图像尺寸 - 720(行)* 1280(列)

相机看到的校准图案

链接中有使用的校准图案图片。

新编辑:

遵循右手定则的世界坐标系及其在图像中对应的点

这个链接包含了世界坐标系的图片以及在图像平面上对应的点

左侧正方形是我的世界坐标系,边长为12.8厘米,左上角是世界原点(0,0)。红色点是在图像中检测到的三维世界点。

所看到的图像是鱼眼镜头相机径向畸变校正后的结果。

相机参数

cameraMatrix_Front=[908.65   0     642.88
                     0     909.28   364.95
                     0        0        1]

distCoeffs_Front=[-0.4589, 0.09462, -1.46*10^-3, 1.23*10^-3]

OpenCV C++ 代码:

vector<Point3f> front_object_pts;
Mat rvec_front;
Mat tvec_front;
Mat rotation_front;
Mat world_position_front_cam;


//Fill front object points(x-y-z order in cms)
//It is square of side 12.8cms on Z=0 plane
front_object_pts.push_back(Point3f(0, 0, 0));
front_object_pts.push_back(Point3f(-12.8, 0, 0));
front_object_pts.push_back(Point3f(-12.8,12.8,0));
front_object_pts.push_back(Point3f(0, 12.8, 0));


//Corresponding Image points detected in the same order as object points
front_image_pts.push_back(points_front[0]);
front_image_pts.push_back(points_front[1]);
front_image_pts.push_back(points_front[2]);
front_image_pts.push_back(points_front[3]);

//Detected points in image matching the 3-D points in the same order
//(467,368)
//(512,369)
//(456,417)
//(391,416)

//Get rvec and tvec using Solve PnP
solvePnP(front_object_pts, front_image_pts, cameraMatrix_Front,
         Mat(4,1,CV_64FC1,Scalar(0)), rvec_front, tvec_front, false, CV_ITERATIVE);

//Output of SolvePnP
//tvec=[-26.951,0.6041,134.72]  (3 x 1 matrix)
//rvec=[-1.0053,0.6691,0.3752]  (3 x 1 matrix)


//Check rvec and tvec is correct or not by projecting the 3-D object points to image
vector<Point2f>check_front_image_pts
projectPoints(front_object_pts, rvec_front, tvec_front, 
             cameraMatrix_Front, distCoeffs_Front, check_front_image_pts);


//Here to note that I have made **distCoefficents**, 
//a 0 vector since my   image points are detected after radial distortion is removed

//Get rotation matrix
Rodrigues(rvec_front, rotation_front);

//Get rotation matrix inverse
Mat rotation_inverse;
transpose(rotation_front, rotation_inverse);

//Get camera position in world cordinates
world_position_front_cam = -rotation_inverse * tvec_front;

//相机的实际位置(手动测量近似值)

X=-47厘米

Y=18厘米

Z=25厘米

//获取的位置

X=-110厘米

Y=71厘米

Z=40厘米

提前致谢。


我似乎遇到了与此处显示的相同的问题。您是否曾经能够解决这个问题? - Orion DeYoe
1个回答

1

你怎么知道cam_worl_pos不正确?

cam_worl_pos是相机的位置。您可以尝试测量相机与三维点所在平面之间的实际距离,并将其与tvecstd::sqrt(tx²+ty²+tz²))的范数进行比较。如果您没有共享代码或不同参数的值,则很难说出问题出在哪里。

编辑

如果您从tvec计算距离,它会给出137.390683厘米std::sqrt(26.951*26.951+0.6041*0.6041+134.72*134.72)

您可以通过测量实际距离来检查是否正确!

还有,您如何手动测量相机相对于世界坐标系的位置?

编辑2

如果您没有得到正确的值,则solvePnP函数的参数存在问题:

  • 你的cameraMatrix_Front看起来是正确的。但请确保908.65 * CCD(mm)= 焦距(mm)
  • 将校准得到的畸变系数的实际值传递给solvePnP函数

  • 你需要至少四个点来进行solvePnP操作(点越多越好),为了获得更高的精度,不要让你的平面(正方形所在的位置)与图像平面平行,如下图所示:

enter image description here

但是更像这样,无论朝哪个方向看: 在此输入图像描述

编辑3

  • 尝试使用不同位置的更多图像,为什么不是实时的并移动相机
  • 确保您在编辑2中要求您做的一切: cameraMatrix_Front,畸变系数等等

嗨,我已经添加了相机参数和OpenCV C++代码,请检查并告诉我。 - Nithin
@Nithin 我刚刚编辑了我的回答!!因为你有x、y和z,所以手动测量相机的位置并不容易!! - Ja_cpp
我使用了一把卷尺,从世界的原点开始……也就是正方形左上角。它应该至少接近这些值,不是那么“偏离”,而我得到的值却不太对。 - Nithin
好的...实际的“距离”大约是70厘米,而使用公式得到的是大约135厘米...所以SolvePnP出了问题...但为什么? - Nithin
我已经添加了使用的校准图案,请检查。现在你可能有更好的想法了。 - Nithin
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接