网资酷

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 149|回复: 1

LIO-SAM角点和平面匹配的残差构建和雅克比推导

[复制链接]

1

主题

3

帖子

3

积分

新手上路

Rank: 1

积分
3
发表于 2022-9-22 11:11:51 | 显示全部楼层 |阅读模式
在阅读LIO-SAM源码的时候,发现点线残差和点面残差和雅克比构建采用了LOAM的表示方法。由于采用了欧拉角构建旋转矩阵,使得雅克比推导和优化方程构建比较复杂,代码也比较难阅读。A-LOAM中使用四元数表示旋转,使用了ceres自动求导,省去了雅可比的推导过程,代码大大简化。LIO-SAM作为一项非常优秀的3D激光SLAM框架,在进行当前帧点云位姿优化的时候使用了Eigen库构造优化过程,后续加入GPS和回环因子又用了gtsam因子图优化,作为对比,gtsam的代码封装性极强,作者把两种优化方式融合到了一个框架中,达到了很好的效果,因此有必要对代码中对应的公式进行推导。
scan2MapOptimization()
点线面残差和雅克比构建主要的代码在LIO-SAM/src/mapOptmization.cpp的scan2MapOptimization()函数中,流程如下:
// 进行角点和平面匹配并构建残差
cornerOptimization();
surfOptimization();

// 将两中特征点匹配的残差组合
combineOptimizationCoeffs();

// 对残差进行一次优化,如果收敛则提前结束
if (LMOptimization(iterCount) == true)
    break;      
点线残差构建
点线残差的定义为点到线的距离,在该直线上取两个点 A=(x1,y1,z1), B=(x2,y2,z2),设当前点为 P=(x0,y0,z0),如下


计算 △PAB的面积,除以AB即可,即
\mathrm{d}=\frac{|\mathbf{PA} \times \mathbf{PB}|}{|\mathbf{AB}|}
\begin{aligned} S_{\triangle A B P} \propto|\overrightarrow{P A} \times \overrightarrow{P B}| \\ \overrightarrow{P A} \times \overrightarrow{P B}=&\left|\begin{array}{ccc} i & j & k \\ x_{1}-x_{0} & y_{1}-y_{0} & z_{1}-z_{0} \\ x_{2}-x_{0} & y_{2}-y_{0} & z_{2}-z_{0} \end{array}\right| \\ =& {\left[\begin{array}{c} \left(y_{1}-y_{0}\right)\left(z_{2}-z_{0}\right)-\left(z_{1}-z_{0}\right)\left(y_{2}-y_{0}\right) \\ \left(z_{1}-z_{0}\right)\left(x_{2}-x_{0}\right)-\left(x_{1}-x_{0}\right)\left(z_{2}-z_{0}\right) \\ \left(x_{1}-x_{0}\right)\left(y_{2}-y_{0}\right)-\left(y_{1}-y_{0}\right)\left(x_{2}-x_{0}\right) \end{array}\right] } \\ \overrightarrow{P A} \times \overrightarrow{P B} \mid &=(\overrightarrow{P A} \times \overrightarrow{P B})^{T}(\overrightarrow{P A} \times \overrightarrow{P B}) \\ &=\left(\left(y_{1}-y_{0}\right)\left(z_{2}-z_{0}\right)-\left(z_{1}-z_{0}\right)\left(y_{2}-y_{0}\right)\right)^{2} \\ &+\left(\left(z_{1}-z_{0}\right)\left(x_{2}-x_{0}\right)-\left(x_{1}-x_{0}\right)\left(z_{2}-z_{0}\right)\right)^{2} \\ &+\left(\left(x_{1}-x_{0}\right)\left(y_{2}-y_{0}\right)-\left(y_{1}-y_{0}\right)\left(x_{2}-x_{0}\right)\right)^{2} \end{aligned}
对应代码中
// 计算 PA x PB 的模长
float a012 = sqrt(((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1)) * ((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1))     
            + ((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1)) * ((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1))   
            + ((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1)) * ((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1)));

// 计算 AB 模长
float l12 = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) + (z1 - z2)*(z1 - z2));

// P 到 AB 的距离
float ld2 = a012 / l12;
点线雅可比计算
分为两步,先对点求导,再对位姿求导
J=\frac{\partial d}{\partial T_{w b}}=\frac{\partial d}{\partial \boldsymbol{p}^{w}} \frac{\partial \boldsymbol{p}^{w}}{\partial \boldsymbol{T}_{w b}}
设 \boldsymbol{p}_{m}=\overrightarrow{P M}=\overrightarrow{P A} \times \overrightarrow{P B} ,残差为:
\begin{aligned} d \propto \sqrt{{ }\left(\left(y_{1}-y_{0}\right)\left(z_{2}-z_{0}\right)-\left(z_{1}-z_{0}\right)\left(y_{2}-y_{0}\right)\right)^{2} \\ +\left(\left(z_{1}-z_{0}\right)\left(x_{2}-x_{0}\right)-\left(x_{1}-x_{0}\right)\left(z_{2}-z_{0}\right)\right)^{2} \\ +\left(\left(x_{1}-x_{0}\right)\left(y_{2}-y_{0}\right)-\left(y_{1}-y_{0}\right)\left(x_{2}-x_{0}\right)\right)^{2}} \\ = \sqrt{\boldsymbol{p}_{m}^{T} \boldsymbol{p}_{m}}  \\ = \sqrt{\left(p_{m x}^{2}+p_{m y}^{2}+p_{m z}^{2}\right)} \end{aligned}
分别对(x0,y0,z0)求导
\begin{aligned} \frac{\partial d}{\partial \boldsymbol{p}^{w}} &=\left[\begin{array}{c} \frac{\partial d}{\partial x_{0}} \\ \frac{\partial d}{\partial y_{0}} \\ \frac{\partial d}{\partial z_{0}} \end{array}\right]^{T} \\ & \propto \frac{1}{2}\left[\begin{array}{c} 2 p_{m y}\left(\left(z_{2}-z_{0}\right)-\left(z_{1}-z_{0}\right)\right)+2 p_{m z}\left(\left(y_{1}-y_{0}\right)-\left(y_{2}-y_{0}\right)\right) \\ 2 p_{m z}\left(\left(x_{2}-x_{0}\right)-\left(x_{1}-x_{0}\right)\right)+2 p_{m x}\left(\left(z_{1}-z_{0}\right)-\left(z_{2}-z_{0}\right)\right) \\ 2 p_{m x}\left(\left(y_{2}-y_{0}\right)-\left(y_{1}-y_{0}\right)\right)+2 p_{m y}\left(\left(x_{1}-x_{0}\right)-\left(x_{2}-x_{0}\right)\right) \end{array}\right]^{T} \\ &=\left[\begin{array}{l} p_{m y}\left(z_{2}-z_{1}\right)+p_{m z}\left(y_{1}-y_{2}\right) \\ p_{m z}\left(x_{2}-x_{1}\right)+p_{m x}\left(z_{1}-z_{2}\right) \\ p_{m x}\left(y_{2}-y_{1}\right)+p_{m y}\left(x_{1}-x_{2}\right) \end{array}\right]^{T} \end{aligned}
对应代码中,代码中对向量|AB||PM|除是为了进行单位化
// 计算残差对点 P 的雅可比且进行单位化
float la = ((y1 - y2)*((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1))
      + (z1 - z2)*((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1))) / a012 / l12;

float lb = -((x1 - x2)*((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1))
       - (z1 - z2)*((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1))) / a012 / l12;

float lc = -((x1 - x2)*((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1))
       + (y1 - y2)*((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1))) / a012 / l12;
点面残差计算
点到的平面的距离作为残差,对系数进行归一化处理,则计算方式为:
d_{h}=\frac{\left|pa  \cdot x_{0}+ pb  \cdot y_{0}+ pc  \cdot z_{0}+pd\right|}{\sqrt{pa^{2}+pb^{2}+pc^{2}}}=\left|pa  \cdot x_{0}+pb  \cdot y_{0}+ pc  \cdot z_{0}+pd\right|
对应代码为:
// 构建超定方程
for (int j = 0; j < 5; j++) {
    matA0(j, 0) = laserCloudSurfFromMapDS->points[pointSearchInd[j]].x;
    matA0(j, 1) = laserCloudSurfFromMapDS->points[pointSearchInd[j]].y;
    matA0(j, 2) = laserCloudSurfFromMapDS->points[pointSearchInd[j]].z;
}

// 求解平面法向量,并单位化,单位化后的平面方程为 Ax + By + Cz + D = 0, A^2 + B^2 + C^2 = 1
matX0 = matA0.colPivHouseholderQr().solve(matB0);

float pa = matX0(0, 0);
float pb = matX0(1, 0);
float pc = matX0(2, 0);
float pd = 1;

float ps = sqrt(pa * pa + pb * pb + pc * pc);
pa /= ps; pb /= ps; pc /= ps; pd /= ps;

// 对每个点计算点到平面的距离,只有都在 0.2m 范围内才认为这个平面匹配是准的
bool planeValid = true;
for (int j = 0; j < 5; j++) {
    if (fabs(pa * laserCloudSurfFromMapDS->points[pointSearchInd[j]].x +
             pb * laserCloudSurfFromMapDS->points[pointSearchInd[j]].y +
             pc * laserCloudSurfFromMapDS->points[pointSearchInd[j]].z + pd) > 0.2) {
        planeValid = false;
        break;
    }
}

if (planeValid) {
    // 用点到的平面的距离作为残差(带符号)
    float pd2 = pa * pointSel.x + pb * pointSel.y + pc * pointSel.z + pd;
点面雅可比计算
用法向量作为雅可比,方向由 pd2 决定
// 用法向量作为雅可比,方向由 pd2 间接决定
coeff.x = s * pa;
coeff.y = s * pb;
coeff.z = s * pc;
coeff.intensity = s * pd2;
点线面残差对位姿的雅可比
\text { mat } A=\left[\begin{array}{c} \frac{\partial d}{\partial \text { roll }} \\ \frac{\partial d}{\partial p i t c h} \\ \frac{\partial d}{\partial y a w} \\ \frac{\partial d}{\partial t_{x}} \\ \frac{\partial d}{\partial t_{y}} \\ \frac{\partial d}{\partial t_{z}} \end{array}\right]
对平移的雅可比
雅可比推导分为两步,残差对点的雅可比和点对位姿的雅可比,下面推导点对位姿的雅可比
设 Lidar 相对于世界坐标系旋转矩阵为R ,平移为t ,将 Lidar 坐标系下的点转为世界坐标系的过程为:
\boldsymbol{p}^{w}=\boldsymbol{R} \boldsymbol{p}+\boldsymbol{t}
对平移的推导很简单,即
\frac{\partial \boldsymbol{p}^{w}}{\partial \boldsymbol{t}}=\frac{\partial \boldsymbol{R} \boldsymbol{p}+\boldsymbol{t}}{\partial \boldsymbol{t}}=\boldsymbol{I}
对应代码中
matA.at<float>(i, 3) = coeff.z;
matA.at<float>(i, 4) = coeff.x;
matA.at<float>(i, 5) = coeff.y;
对旋转的雅可比
LOAM 原作者选择的是 ZXY 外旋(沿固定 Z 轴旋转-> 沿固定 X 轴旋转 -> 沿固定 Y 轴旋转)表示,由于外旋的旋转矩阵顺序为作乘,因此 ZXY 内旋的旋转矩阵的计算方式为:R=RyRxRz,即:
\begin{aligned} \boldsymbol{R} &=\boldsymbol{R}_{y} \boldsymbol{R}_{x} \boldsymbol{R}_{z} \\ &=\left[\begin{array}{ccc} \cos (ry) & 0 & \sin (ry) \\ 0 & 1 & 0 \\ -\sin (ry) & 0 & \cos (ry) \end{array}\right]\left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & \cos (rx) & -\sin (rx) \\ 0 & \sin (rx) &  \cos (rx) \end{array}\right]\left[\begin{array}{ccc} \cos (rz) & -\sin (rz) & 0 \\ \sin (rz) & \cos (rz) & 0 \\ 0 & 0 & 1 \end{array}\right] \\ &=\left[\begin{array}{ccc} \cos (ry) \cos (rz)+\sin (ry) \sin (rx) \sin (rz) & \cos (rz) \sin (ry) \sin (rx)-\cos (ry) \sin (rz) & \cos (rx) \sin (ry) \\ \cos (rx) \sin (rz) & \cos (rx) \cos (rz) & -\sin (rx) \\ \cos (ry) \sin (rx) \sin (rz)-\cos (rz) \sin (ry) & \cos (ry) \cos (rz) \sin (rx)+\sin (ry) \sin (rz) & \cos (ry) \cos (rx) \end{array}\right] \end{aligned}
平移对旋转求导为0,忽略
点对rx求雅可比有:
\frac{\partial(\boldsymbol{R} \boldsymbol{p})}{\partial rx}=\left[\begin{array}{c} (\sin (ry) \cos (rx) \sin (rz)) p_{x}+(\cos (rz) \sin (ry) \cos (rx)) p_{y}-(\sin (rx) \sin (ry)) p_{z} \\ -(\sin (rx) \sin (rz)) p_{x}-(\sin (rx) \cos (rz)) p_{y}-(\cos (rx)) p_{z} \\ (\cos (ry) \cos (rx) \sin (rz)) p_{x}+(\cos (ry) \cos (rz) \cos (rx)) p_{y}-(\cos (ry) \sin (rx)) p_{z} \end{array}\right]
上式为点对位姿的雅可比,乘以残差对点的雅可比(coeff.x,coeff.y,coeff.z),得到对应代码中:
// 进行 ZXY 外旋定义坐标系下的雅可比计算
float arx = (crx*sry*srz*pointOri.x + crx*crz*sry*pointOri.y - srx*sry*pointOri.z) * coeff.x
      + (-srx*srz*pointOri.x - crz*srx*pointOri.y - crx*pointOri.z) * coeff.y
      + (crx*cry*srz*pointOri.x + crx*cry*crz*pointOri.y - cry*srx*pointOri.z) * coeff.z;
点对ry求雅可比有:
\frac{\partial(\boldsymbol{R} \boldsymbol{p})}{\partial ry}=\left[\begin{array}{c} (-\sin (ry) \cos (rz)+\cos (ry) \sin (rx) \sin (rz)) p_{x}+(\cos (rz) \cos (ry) \sin (rx)+\sin (ry) \sin (rz)) p_{y}+(\cos (rx)  \cos (ry)) p_{z} \\ 0 \\ (-\sin (ry) \sin (rx) \sin (rz)-\cos (rz) \cos (ry)) p_{x}+(-\sin (ry) \cos (rz) \sin (rx)+\cos (ry) \sin (rz)) p_{y}-(\sin (ry) \cos (rx)) p_{z} \end{array}\right]
对应代码中:
float ary = ((cry*srx*srz - crz*sry)*pointOri.x
      + (sry*srz + cry*crz*srx)*pointOri.y + crx*cry*pointOri.z) * coeff.x
      + ((-cry*crz - srx*sry*srz)*pointOri.x
      + (cry*srz - crz*srx*sry)*pointOri.y - crx*sry*pointOri.z) * coeff.z;
点对rz求雅可比有:
\frac{\partial(\boldsymbol{R} \boldsymbol{p})}{\partial rz}=\left[\begin{array}{c} (-\cos (ry) \sin (rz)+\sin (ry) \sin (rx) \cos (rz)) p_{x}+(-\sin (rz) \sin (ry) \sin (rx)-\cos (ry) \cos (rz)) p_{y} \\ (\cos (rx) \cos (rz)) p_{x}-(\cos (rx) \sin (rz)) p_{y} \\ (\cos (ry) \sin (rx) \cos (rz)+\sin (rz) \sin (ry)) p_{x}+(-\cos (ry) \sin (rz) \sin (rx)+\sin (ry) \cos (rz)) p_{y} \end{array}\right]
对应代码中:
float arz = ((crz*srx*sry - cry*srz)*pointOri.x + (-cry*crz-srx*sry*srz)*pointOri.y)*coeff.x
      + (crx*crz*pointOri.x - crx*srz*pointOri.y) * coeff.y
      + ((sry*srz + cry*crz*srx)*pointOri.x + (crz*sry-cry*srx*srz)*pointOri.y)*coeff.z;
至此雅可比推导完毕,接下来构建方程进行求解
J^{T} J \Delta x=-J \cdot f(x)
对应代码中:
matA.at<float>(i, 0) = arz;
matA.at<float>(i, 1) = arx;
matA.at<float>(i, 2) = ary;
matA.at<float>(i, 3) = coeff.z;
matA.at<float>(i, 4) = coeff.x;
matA.at<float>(i, 5) = coeff.y;
matB.at<float>(i, 0) = -coeff.intensity;


// QR 分解求解 Hx=b
cv::transpose(matA, matAt);
matAtA = matAt * matA;
matAtB = matAt * matB;
cv::solve(matAtA, matAtB, matX, cv::DECOMP_QR);
更新位姿优化增量:
/// 更新当前关键帧全局位姿估计
transformTobeMapped[0] += matX.at<float>(0, 0);
transformTobeMapped[1] += matX.at<float>(1, 0);
transformTobeMapped[2] += matX.at<float>(2, 0);
transformTobeMapped[3] += matX.at<float>(3, 0);
transformTobeMapped[4] += matX.at<float>(4, 0);
transformTobeMapped[5] += matX.at<float>(5, 0);
参考:
1、https://blog.csdn.net/weixin_37835423/article/details/111587379
2、https://zhuanlan.zhihu.com/p/57351961
3、基于 LOAM 的方法中平面点和边缘线的残差构建以及雅可比推导
4、wykxwyc的博客 | wykxwyc's Blog
回复

使用道具 举报

0

主题

1

帖子

2

积分

新手上路

Rank: 1

积分
2
发表于 2025-2-15 05:19:03 | 显示全部楼层
我只是路过,不发表意见
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|网资酷

GMT+8, 2025-3-14 23:16 , Processed in 0.087708 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表