位姿估计和坐标系变换

SLAM是一个“鸡生蛋和蛋生鸡”的问题,要定位需要重建,一般通过当前sensor看到到场景跟建好的地图进行匹配确定自身的位置。简单的例子:比如你在平面上,别人问你的坐标,那么很显然你得先有坐标系。要重建又需要精确的定位信息,如果没有相机位姿,那么当前帧数据无法统一注册到世界坐标系下。

在SLAM中,所谓的位姿其实指的是相机在世界坐标系中的位姿。位姿包括两方面:位置和姿势,即三维坐标和朝向。如下所示,建图的过程就需要知道每一刻相机的位姿,从而将当前相机捕获的点云注册到全局的点云模型中。
在这里插入图片描述
常用的变换有:世界坐标系 -> 相机坐标系相机的位姿 -> 世界坐标系
如下所示:世界坐标系为 w x y wxy wxy, 相机坐标系为 c x ’ y ’ cx^’y^’ cxy P P P在世界坐标下的坐标为 ( a , b ) (a,b) (a,b), P P P在相机坐标系下的坐标为 ( a ’ b ’ ) (a^’b^’) (ab)

(1) 已知相机坐标系在世界坐标系的位姿为: T c w T_{cw} Tcw, 世界坐标中的点 P w P_w Pw, 那么相机坐标系的坐标为 P c = T c w − 1 P w P_c = T^{-1}_{cw}P_w Pc=Tcw1Pw
(2) 已知相机坐标系在世界坐标系的位姿为: T c w T_{cw} Tcw, 相机坐标中的点 P c P_c Pc, 那么世界坐标系的坐标为 P w = T c w P c P_w = T_{cw}P_c Pw=TcwPc

T c w T_{cw} Tcw T c w − 1 T^{-1}_{cw} Tcw1均可作为相机位姿, 主流的如ORBSLAM采用后者作为相机的位姿。
在这里插入图片描述
可以检验一下:
(1)只包含平移,相机坐标系在世界坐标下只有平移,平移向量为 ( 2 , 2 ) (2,2) (2,2), 那么 T c w = [ 1 0 2 0 1 2 0 0 1 ] T_{cw} = \begin{bmatrix} 1 & 0 & 2\\ 0 & 1 & 2\\ 0 & 0 & 1 \end{bmatrix} Tcw=100010221 T c w − 1 = [ 1 0 − 2 0 1 − 2 0 0 1 ] T^{-1}_{cw} = \begin{bmatrix} 1 & 0 & -2\\ 0 & 1 & -2\\ 0 & 0 & 1 \end{bmatrix} Tcw1=100010221
已知世界坐标系中的坐标为 P w ( 3 , 3 ) P_w(3,3) Pw(3,3), 转换到相机坐标系下为: P c = T c w − 1 P w = [ 1 0 − 2 0 1 − 2 0 0 1 ] ∗ [ 3 3 1 ] = [ 1 1 1 ] P_c = T^{-1}_{cw} P_w = \begin{bmatrix} 1 & 0 & -2\\ 0 & 1 & -2\\ 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} 3 \\ 3 \\ 1 \end{bmatrix} = \begin{bmatrix} 1 \\ 1 \\ 1 \end{bmatrix} Pc=Tcw1Pw=100010221331=111。因此,相机坐标系下的坐标 P c = ( 1 , 1 ) P_c = (1,1) Pc=(1,1)
反之,已知相机坐标系下的坐标 P c ( 1 , 1 ) P_c(1,1) Pc(1,1), 转换到世界坐标系下为: P w = T c w P c = [ 1 0 2 0 1 2 0 0 1 ] ∗ [ 1 1 1 ] = [ 3 3 1 ] P_w = T_{cw} P_c = \begin{bmatrix} 1 & 0 & 2\\ 0 & 1 & 2\\ 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} 1 \\ 1 \\ 1 \end{bmatrix} = \begin{bmatrix} 3 \\ 3 \\ 1 \end{bmatrix} Pw=TcwPc=100010221111=331, 因此,世界坐标系下的坐标 P w = ( 3 , 3 ) P_w = (3,3) Pw=(3,3)
在这里插入图片描述
(2)只包含旋转, 相机坐标系在世界坐标系中逆时针旋转了 180 ° 180\degree 180°, 那么位姿矩阵 T c w = [ − 1 0 0 0 − 1 0 0 0 1 ] T_{cw} = \begin{bmatrix} -1 & 0 & 0\\ 0 & -1 & 0\\ 0 & 0 & 1 \end{bmatrix} Tcw=100010001, T c w − 1 = [ − 1 0 0 0 − 1 0 0 0 1 ] T^{-1}_{cw} = \begin{bmatrix} -1 & 0 & 0\\ 0 & -1 & 0\\ 0 & 0 & 1 \end{bmatrix} Tcw1=100010001,

已知世界坐标系中的坐标为 P w ( 3 , 3 ) P_w(3,3) Pw(3,3), 转换到相机坐标系下为 P c = T c w − 1 P w = ( − 3 , − 3 ) P_c = T^{-1}_{cw} P_w = (-3,-3) Pc=Tcw1Pw=(3,3)
反之,相机坐标下的坐标为 P c ( − 3 , − 3 ) P_c(-3,-3) Pc(3,3), 转换到世界坐标系下为 P w = T c w P c = ( 3 , 3 ) P_w = T_{cw}P_c = (3,3) Pw=TcwPc=(3,3)

(3)既包含旋转又包含平移,先逆时针旋转 180 ° 180\degree 180°, 然后平移 ( 2 , 2 ) (2,2) (2,2), 因此 T c w = [ 0 − 1 2 1 0 2 0 0 1 ] T_{cw} = \begin{bmatrix} 0 & -1 & 2\\ 1 & 0 & 2\\ 0 & 0 & 1 \end{bmatrix} Tcw=010100221, T c w − 1 = [ 0 1 − 2 − 1 0 2 0 0 1 ] T^{-1}_{cw} = \begin{bmatrix} 0 & 1 & -2\\ -1 & 0 & 2\\ 0 & 0 & 1 \end{bmatrix} Tcw1=010100221,
已知世界坐标系中的坐标为 P w ( 2 , 2 ) P_w(2,2) Pw(2,2), 转换到相机坐标系下为 P c = T c w − 1 P w = ( 0 , 0 ) P_c =T^{-1}_{cw} P_w = (0,0) Pc=Tcw1Pw=(0,0)
已知世界坐标系中的坐标为 P w ( 3 , 3 ) P_w(3,3) Pw(3,3), 转换到相机坐标系下为 P c = T c w − 1 P w = ( 1 , − 1 ) P_c =T^{-1}_{cw} P_w = (1,-1) Pc=Tcw1Pw=(1,1)
反之,已知相机坐标系中的坐标为 P c ( 0 , 0 ) P_c(0,0) Pc(0,0), 转换到相机坐标系下为 P w = T c w P c = ( 2 , 2 ) P_w =T_{cw} P_c = (2,2) Pw=TcwPc=(2,2)

在 OpenCV 中,可以使用 PnP(Perspective-n-Point)算法来估计两张图像之间的位姿。PnP 算法是一种基于相机内参和三维点云的姿态估计方法,可以根据图片中的特征点和三维点云计算出相机在空间中的位置和方向。 以下是 OpenCV 中实现 PnP 算法的大致步骤: 1. 从两张图像中提取 SIFT 或 SURF 特征点,并进行匹配,得到一组匹配点对。 2. 根据匹配点对,估计出三维空间中的点云。 3. 定义相机内参矩阵,通过 PnP 算法计算相机外参矩阵(即相机在世界坐标系中的位置和方向)。 4. 通过相机内参矩阵和外参矩阵,将三维点云投影到二维平面上,与原始图片进行比较,计算误差并调整相机内参和外参矩阵。 5. 重复以上步骤,直到误差满足要求。 以下是一个简单的 Python 代码示例,展示了如何使用 OpenCV 中的 PnP 算法进行位姿估计: ```python import cv2 import numpy as np # 读取两张图片 img1 = cv2.imread('img1.jpg') img2 = cv2.imread('img2.jpg') # 提取 SIFT 特征点并进行匹配 sift = cv2.xfeatures2d.SIFT_create() kp1, des1 = sift.detectAndCompute(img1, None) kp2, des2 = sift.detectAndCompute(img2, None) bf = cv2.BFMatcher() matches = bf.match(des1, des2) # 选取最优匹配点对 matches = sorted(matches, key=lambda x: x.distance) good_matches = matches[:50] pts1 = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2) pts2 = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2) # 估计相机位姿 K = np.array([[800, 0, 320], [0, 800, 240], [0, 0, 1]]) dist_coefs = np.zeros(5) success, rvec, tvec = cv2.solvePnP(pts1, pts2, K, dist_coefs) # 打印相机位姿 print("Rotation vector:\n", rvec) print("Translation vector:\n", tvec) ``` 需要注意的是,以上代码仅仅只是一个简单的示例,实际应用中还需要进行一些额外的处理,例如去除误匹配点等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Researcher-Du

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值