引言
PNP问题的描述以及定义是相对简单的,他的目的就是求解3D-2D点对运动的方法。简单来说,就是 在已知n个三维空间点坐标(相对于某个指定的坐标系A)及其二维投影位置的情况下,如何估计相机的位姿(即相机在坐标系A下的姿态)。
举个例子,我们在一幅图像中,知道其中至少四个图像中确定的点在3D空间下的相对坐标位置,我们就可以估计出相机相对于这些点的姿态,或者说估计出这些3D点在相机坐标系下姿态。(上述说的姿态或者位姿,包括位置以及方向,即一个6自由度的状态) [1.]
PnP 问题有很多种求解方法,例如用三对点估计位姿的 P3P 、直接线性变换(DLT)、EPnP、SDP、UPnP。此外,还能用非线性优化的方式,构建最小二乘问题并迭代求解,也就是万金油式的 Bundle Adjustment [2.] 。
- [x] Edit By Porter, 积水成渊,蛟龙生焉。
- [x] Insert Date String 插件,ctrl+shift+I 插入时间字符串
pnp 求解过程
Perspective-n-Point问题(PnP)的已知条件:
- n个世界坐标系中的3D参考点(3D reference points)坐标;
- 与这n个3D点对应的、投影在图像上的2D参考点(2D reference points)坐标;
- 摄像头的内参K KK;
- 求解PnP问题可以得到摄像头的位姿。
OpenCV中提供了solvePnP函数可以直接求解出旋转矩阵和平移矩阵。
pnp 求解原理
对于视觉里程计中,相机位姿的求解问题极为常见。对于双目相机,由于其可以直接计算出深度信息,所以在相机位姿求解上十分容易。但如果我们使用的是单目相机,如何从二维图像中求解出相机相对三维物体的位姿就需要一定的算法来完成 [7.] 。
此部分按照《视觉slam十四讲》做了个笔记,直接线性变换仅仅需要6对3d-2d匹配点,即可求解出相机3d到2d的 R∣t 矩阵。
考虑空间一点 P=(X,Y,Z,1)T。 在图像 I1 中投影到图像特征点 x1=(u1,v1,1)T (以归一化平面齐次坐标表示)。我们需要求解相机位姿 R,t ,与单应矩阵的求解类似,我们定义增广矩阵 [R∣T] 为一个3x4的矩阵,包含了旋转平移信息。将其展开如下形式
⎝⎛u1v11⎠⎞=⎝⎛t1t5t9t2t6t10t3t7t11t4t8t12⎠⎞⎝⎜⎜⎜⎛XYZ1⎠⎟⎟⎟⎞
用最后一行把s消除掉,得到两个约束(一对特征点,对应两个约束)
u1=t9X+t10Y+t11Z+t12t1X+t2Y+t3Z+t4
v1=t9X+t10Y+t11Z+t12t5X+t6Y+t7Z+t8
为了简化表示,定义 T 的行向量
t1=(t1,t2,t3,t4)T
t2=(t5,t6,t7,t8)T
t3=(t9,t10,t11,t12)T
于是有
t1TP−t3TPu1=0,
t2TP−t3TPv1=0
请注意 t是待求变量,可以看到,每个特征点提供两个关于 t 的线性约束,假设一共存在N对特征点,则可以列出如下线性方程:
⎝⎜⎜⎜⎜⎜⎛P1T0...PNT00P1T....0PNT−u1P1T−v1P1T...−uNP1T−vNP1T⎠⎟⎟⎟⎟⎟⎞
于是6对特诊点,即可得到12组方程式,正好对应12个待求变量 t 直接求解即可得到变量值。这种方法称为DLT。
直接求解中,当匹配点对大于6个点时, 也可以用SVD [11.] 等方法对超定方程求最小二乘解。
P3P
可以参考前面一篇双目相机标定的文章,以及slam 十四讲里面的介绍。
与其他方法相比,EPnP方法的复杂度为O(n),对于点对数量较多的PnP问题,非常高效。
核心思想是将3D点表示为4个控制点的组合,优化也只针对4个控制点,所以速度很快,在求解
Mx=0 时,最多考虑了4个奇异向量,因此精度也很高。
AP3P
参考 opencv 的官方介绍 [13.]
UPnP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| vector<Point3d> World_Coor = {Point3f(0, 0, 0), Point3f(0, 26.5, 0), Point3f(67.5, 26.5, 0), Point3f(67.5, 0, 0)};
vector<Point2d> Img_Coor; Img_Coor.push_back(featrue[i].bl()); Img_Coor.push_back(featrue[i].tl()); Img_Coor.push_back(featrue[i].tr()); Img_Coor.push_back(featrue[i].br());
solvePnP(objectSmallArmor, img_points, cameraMatrix, distcoeff, rvec, tvec, false, SOLVEPNP_IPPE); Rodrigues(rvec, R_rvec);
R_rvec.convertTo(R_rvec, CV_64FC1); tvec.convertTo(tvec, CV_64FC1);
Eigen::Matrix3f Rotated_matrix; Eigen::Vector3f Tran_vector; cv2eigen(R_rvec, Rotated_matrix); cv2eigen(tvec, Tran_vector);
Eigen::Vector3f euler_angles = Rotated_matrix.eulerAngles(0, 1, 2);
picth = euler_angles[0] * 180 / PI; yaw = euler_angles[1] * 180 / PI; roll = euler_angles[2] * 180 / PI;
distance = (COEFF_K * sqrt(Tran_vector.transpose() * Tran_vector) + COEFF_B) * cosf(pitch * PI / 180.f);
|
参考文献
1. PNP(pespective-n-point)算法学习笔记
2. 3D-2D:PnP算法原理
3. 深入EPnP算法
4. 单目相机位姿求解之PNP算法原理剖析与实践
5. EPro-PnP: Generalized End-to-End Probabilistic Perspective-n-Points for Monocular Object Pose Estimation
6. 【论文笔记】—目标姿态估计—EPro-PnP—2022-CVPR
7. 单目相机位姿求解之PNP算法原理剖析与实践
8. 直接线性变换DLT
9. 双目视觉算法研究(二)相机模型和直接线性法(DLT)
10. 《slam十四讲》中的视觉里程计一章
11. SVD-矩阵奇异值分解 —— 原理与几何意义
12. EPnP原理与源码详解
13. Perspective-n-Point (PnP) pose computation