Vins-Fusion——三角化triangulate

继上一篇博文Vins-Fusion初始化位姿——3D-2D:PNP求解当前帧位姿,本文继续介绍Vins-Fusion双目初始化时,三角化triangulate。

一、三角化triangulate

三角化triangulate是根据特征点在多个相机下的投影恢复出特征点的3D位置。

二、三角化求解流程

1.遍历当前帧特征点,若该特征点深度为正,说明已经三角化了。
// 已经三角化过
if (it_per_id.estimated_depth > 0)
	continue;
2.双目首帧三角化

三角化是根据多个相机下的投影恢复出特征点的3D位置,需要已知相机位姿和投影像素位置(归一化相机平面像素坐标)

(1)左右目位姿

左目起始帧start_frame位姿

// 起始观测帧位姿 Tcw
int imu_i = it_per_id.start_frame;
Eigen::Matrix<double, 3, 4> leftPose;
Eigen::Vector3d t0 = Ps[imu_i] + Rs[imu_i] * tic[0];
Eigen::Matrix3d R0 = Rs[imu_i] * ric[0];
leftPose.leftCols<3>() = R0.transpose();
leftPose.rightCols<1>() = -R0.transpose() * t0;

右目起始帧start_frame位姿

// 起始观测帧位姿Tcw
Eigen::Matrix<double, 3, 4> rightPose;
Eigen::Vector3d t1 = Ps[imu_i] + Rs[imu_i] * tic[1];
Eigen::Matrix3d R1 = Rs[imu_i] * ric[1];
rightPose.leftCols<3>() = R1.transpose();
rightPose.rightCols<1>() = -R1.transpose() * t1;
(2)左右目归一化相机平面像素坐标
// 取左右目对应的归一化相机平面点
Eigen::Vector2d point0, point1;
Eigen::Vector3d point3d;
point0 = it_per_id.feature_per_frame[0].point.head(2);
point1 = it_per_id.feature_per_frame[0].pointRight.head(2);

注:it_per_id.feature_per_frame[0].point.head(2),表示左目归一化相机平面的前两个数据,即x, y。

(3)三角化

有了位姿和对应的投影位置就可以三角化求路标点了(3D坐标)

triangulatePoint(leftPose, rightPose, point0, point1, point3d);

//函数原型:
/**
 * SVD计算三角化点
 * @param Pose0     位姿Tcw
 * @param Pose1     位姿Tcw
 * @param point0    归一化相机坐标系平面点
 * @param point1    归一化相机坐标系平面点
 * @param point_3d  output 三角化点,世界坐标系点
*/
void FeatureManager::triangulatePoint(Eigen::Matrix<double, 3, 4> &Pose0, Eigen::Matrix<double, 3, 4> &Pose1,
                        Eigen::Vector2d &point0, Eigen::Vector2d &point1, Eigen::Vector3d &point_3d)
{
    Eigen::Matrix4d design_matrix = Eigen::Matrix4d::Zero();
    design_matrix.row(0) = point0[0] * Pose0.row(2) - Pose0.row(0);
    design_matrix.row(1) = point0[1] * Pose0.row(2) - Pose0.row(1);
    design_matrix.row(2) = point1[0] * Pose1.row(2) - Pose1.row(0);
    design_matrix.row(3) = point1[1] * Pose1.row(2) - Pose1.row(1);
    Eigen::Vector4d triangulated_point;
    triangulated_point =
              design_matrix.jacobiSvd(Eigen::ComputeFullV).matrixV().rightCols<1>();
    point_3d(0) = triangulated_point(0) / triangulated_point(3);
    point_3d(1) = triangulated_point(1) / triangulated_point(3);
    point_3d(2) = triangulated_point(2) / triangulated_point(3);
}

以上部分解析如下:
在这里插入图片描述
疑问点:根据推导design_matrix的1-2行对应代码中的2-1,暂时还不知道为啥?
ps:对于代码中调用Eigen:svd库求解最小二乘Ax = 0问题的理论基础可以参考文章奇异值分解(SVD)方法求解最小二乘问题 ,有问题留言交流。

3.双目非首帧三角化

完成双目首帧三角化后,遍历当前特征点的观测帧,与首帧观测帧构建最小二乘,并用SVD求解,求解过程与首帧类似,具体如下

int imu_i = it_per_id.start_frame, imu_j = imu_i - 1;

Eigen::MatrixXd svd_A(2 * it_per_id.feature_per_frame.size(), 4);
int svd_idx = 0;

Eigen::Matrix<double, 3, 4> P0;
// 首帧观测帧的位姿 Twc
Eigen::Vector3d t0 = Ps[imu_i] + Rs[imu_i] * tic[0];
Eigen::Matrix3d R0 = Rs[imu_i] * ric[0];
P0.leftCols<3>() = Eigen::Matrix3d::Identity();
P0.rightCols<1>() = Eigen::Vector3d::Zero();

// 遍历当前特征点观测帧,与首帧观测帧构建最小二乘,SVD三角化
for (auto &it_per_frame : it_per_id.feature_per_frame)
{
	imu_j++;
	// 当前观测帧位姿 Twc
	Eigen::Vector3d t1 = Ps[imu_j] + Rs[imu_j] * tic[0];
	Eigen::Matrix3d R1 = Rs[imu_j] * ric[0];
	// 与首帧观测帧之间的位姿变换 Tij
	Eigen::Vector3d t = R0.transpose() * (t1 - t0);
	Eigen::Matrix3d R = R0.transpose() * R1;
	// Tji
	Eigen::Matrix<double, 3, 4> P;
	P.leftCols<3>() = R.transpose();
	P.rightCols<1>() = -R.transpose() * t;
	Eigen::Vector3d f = it_per_frame.point.normalized();
	svd_A.row(svd_idx++) = f[0] * P.row(2) - f[2] * P.row(0);
	svd_A.row(svd_idx++) = f[1] * P.row(2) - f[2] * P.row(1);

	if (imu_i == imu_j)
		continue;
}
// todo
ROS_ASSERT(svd_idx == svd_A.rows());
Eigen::Vector4d svd_V = Eigen::JacobiSVD<Eigen::MatrixXd>(svd_A, Eigen::ComputeThinV).matrixV().rightCols<1>();
double svd_method = svd_V[2] / svd_V[3];
//it_per_id->estimated_depth = -b / A;
//it_per_id->estimated_depth = svd_V[2] / svd_V[3];

it_per_id.estimated_depth = svd_method;
//it_per_id->estimated_depth = INIT_DEPTH;

if (it_per_id.estimated_depth < 0.1)
{
	it_per_id.estimated_depth = INIT_DEPTH;
}

以上就完成了Vins-Fusion双目初始化时,三角化triangulate求解特征点的3D位置(路标点)

由来:近期有同学问vins三角化的代码,相关疑问总结如下。
补充:

一、三角化理论对应代码详细流程

1.利用滑窗内首帧观测到该特征点计算其深度;
2.利用外参计算该特征点在世界坐标系下的位姿(R(ck2w), t(ck2w));
3.由于下面三角化需要求得(R(w2ck), t(w2ck)),则需对其转置,如下
在这里插入图片描述
4.最后将归一化相机平面坐标点(point(0)/point(1))和对应的位姿(R/t)进行三角化求解triangulatePoint。

二、代码相关说明

(1)计算滑窗内所有特征点的深度,因为每一个特征点在滑窗内可能被多帧观测到,计算该特征点的深度为观测到该特征点的首帧;
(2)RS:表示b系到w系,tic/ric外参,表示c(camera)系到b系;
(3)三角化只用到滑窗内首帧左右目观测帧,为啥不用所以观测帧求解深度?因为后续会优化调整位姿和三维点。故猜想作者这里只用观测到该特征点的首帧进行三角化。

以上补充,解决了同学的疑问。你呢?有疑问评论区讨论。

参考:

(1)https://blog.csdn.net/u010196944/article/details/127569002?spm=1001.2014.3001.5501
(2)https://blog.csdn.net/u010196944/article/details/127514369?spm=1001.2014.3001.5501

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值