使用gtsam添加OrientedPlane3Factor平面约束因子

news/2025/1/14 15:05:47 标签: 平面, 算法, 人工智能

在基于地面约束的SLAM优化中,已知的地面信息(如 plan.pcd 文件中的地面模型)可以用作一个先验约束,以帮助优化位姿估计。具体而言,这个过程涉及将地面模型和每个帧的位姿结合,以创建一个因子模型,然后利用该因子模型在图优化过程中约束位姿。

以下是一个简化的工作流程,描述了如何使用已知地面模型对位姿进行优化:

  1. 地面模型的提取

    • plan.pcd 文件中提取地面的平面参数。通常,这包括平面方程的法向量和一个偏移量。这可以通过PCL(Point Cloud Library)的平面分割工具如RANSAC实现。
  2. GTSAM因子图初始化

    • 使用GTSAM的因子图模型,比如 NonlinearFactorGraph,以构建整个SLAM问题。
  3. 定义地面约束

    • 创建 OrientedPlane3Factor,这个因子将平面模型(提取自 plan.pcd)与每个帧的位姿关联。它定义了地面应该如何与这些位姿对齐。
  4. 添加因子到因子图中

    • 将每帧的位姿和对应的 OrientedPlane3Factor 添加到因子图中。这个因子会考虑当前位姿与地面模型之间的偏差,并用来优化位姿。
  5. 位姿优化

    • 利用GTSAM中的优化工具(如Levenberg-Marquardt优化器),根据定义的因子图对所有位姿进行优化。过程中的关键是通过地面因子提供的约束减少累积的位姿误差。
  6. 结果应用

    • 优化后,新生成的位姿序列会使得每个帧的位姿对齐到地面模型给予的参考系中。通常,这意味着消除由传感器噪声、漂移或累积误差引入的偏差。

通过以上过程,地面模型被用于约束和改善传感器估计的轨迹,提供一个更稳定和准确的位姿方案。通过这种综合约束模式,尤其是在运行中的环境几何形状已知的情况下,能显著提高定位的精度和鲁棒性。

OrientedPlane3Factor 是一种用于约束平面和位姿之间关系的因子,在图优化中用于减少位姿估计的漂移和误差。要理解这个因子如何计算位姿与地面模型之间的偏差,我们需要深入了解其工作机制和数学基础。

示例:

在slam中对一系列点云帧添加地平面约束,我们需要对每一帧都进行地面平面的提取,然后利用GTSAM来添加 OrientedPlane3Factor。以下是如何实现这一过程的代码示例,它将对1000帧点云进行处理,并对相应的位姿进行优化

#include <gtsam/geometry/OrientedPlane3.h>
#include <gtsam/nonlinear/NonlinearFactorGraph.h>
#include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h>
#include <gtsam/nonlinear/Values.h>
#include <gtsam/slam/PriorFactor.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <iostream>
#include <string>

// Function to extract plane coefficients from a PCD file
Eigen::Vector4f extractPlaneCoefficients(const std::string& file_path) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

    if (pcl::io::loadPCDFile<pcl::PointXYZ>(file_path, *cloud) == -1) {
        PCL_ERROR("Couldn't read file %s\n", file_path.c_str());
        exit(-1);
    }

    pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
    pcl::SACSegmentation<pcl::PointXYZ> seg;
    seg.setOptimizeCoefficients(true);
    seg.setModelType(pcl::SACMODEL_PLANE);
    seg.setMethodType(pcl::SAC_RANSAC);
    seg.setDistanceThreshold(0.01);

    pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
    seg.setInputCloud(cloud);
    seg.segment(*inliers, *coefficients);

    if (coefficients->values.size() != 4) {
        PCL_ERROR("Could not estimate a planar model for the given dataset.\n");
        exit(-1);
    }

    return Eigen::Vector4f(coefficients->values[0], coefficients->values[1], coefficients->values[2], coefficients->values[3]);
}

int main() {
    // Assume poses is an array that holds the pose of each frame obtained from SLAM
    std::vector<gtsam::Pose3> poses(1000);

    // Initialize the poses here or from your SLAM results. This is just a placeholder.
    for (int i = 0; i < 1000; ++i) {
        poses[i] = gtsam::Pose3(); // Replace with initial poses
    }

    // Create a factor graph
    gtsam::NonlinearFactorGraph graph;

    // Initialize values
    gtsam::Values initial;

    // Create a noise model for the plane factor
    auto noiseModel = gtsam::noiseModel::Isotropic::Sigma(3, 0.1);

    for (int i = 0; i < 1000; ++i) {
        // Extract plane coefficients for the ith point cloud
        std::string file_path = "path/to/cloud/plane_" + std::to_string(i) + ".pcd";
        Eigen::Vector4f planeCoefficients = extractPlaneCoefficients(file_path);

        // Convert to GTSAM's OrientedPlane3
        gtsam::OrientedPlane3 groundPlane(planeCoefficients.head<3>(), planeCoefficients[3]);

        // Add the OrientedPlane3Factor for each pose
        graph.emplace_shared<gtsam::PriorFactor<gtsam::OrientedPlane3>>(i, groundPlane, noiseModel);

        // Insert the corresponding initial pose into the values
        initial.insert(i, poses[i]);
    }

    // Optimize the graph
    gtsam::LevenbergMarquardtOptimizer optimizer(graph, initial);
    gtsam::Values result = optimizer.optimize();

    // Retrieve and print the optimized poses
    for (int i = 0; i < 1000; ++i) {
        gtsam::Pose3 optimizedPose = result.at<gtsam::Pose3>(i);
        std::cout << "Optimized Pose " << i << ": " << optimizedPose << std::endl;
    }

    return 0;
}

OrientedPlane3和OrientedPlane3Factor

  1. OrientedPlane3:

    • 描述: 这是GTSAM中用于表示三维空间中平面的一种数据结构。一个平面通常通过其法向量 ( \mathbf{n} = (a, b, c) ) 以及距离原点的距离 ( d ) 来定义。
    • 平面方程: ( ax + by + cz + d = 0 )
  2. OrientedPlane3Factor:

    • 作用: 这个因子将一个 OrientedPlane3 与一个 Pose3 (三维位姿) 联系起来,用于检查位姿在优化过程中是否遵循平面约束。
    • 目的: 确保优化后的位姿(例如相机或激光雷达的位姿)在空间中保持与已知平面之间的几何关系。

计算位姿与地面偏差

OrientedPlane3Factor 的目的在于计算当前位姿(如相机或激光雷达的坐标系)与定义的地面模型之间的几何误差,并将此误差用于优化流程中。

  1. 误差计算:

    • 当一个 Pose3 被应用到一个 OrientedPlane3 时,计算的目标是看看变换后的平面与其在地图坐标系中记录的模型间的差异。
    • 这个误差可以看作是在当前位姿下,地图中的平面和传感器估计平面间的距离或角度偏差。
  2. 误差方程:
    在这里插入图片描述

  3. 优化目标:

    • 在图优化期间,OrientedPlane3Factor 被用来引导优化算法最小化以上误差。利用Levenberg-Marquardt等非线性优化方法,逐步调整各关键帧位姿,使得增量误差不断降低。

通过这种方式,OrientedPlane3Factor 提供了一种将全局或相对不变的地面模型信息引入到基于视觉或激光的SLAM系统中,以强化其对全局坐标的约束,而不仅仅依赖于相对运动估计。此优化处理将有助于减少累积误差, 提供更可靠的位姿估计。


http://www.niftyadmin.cn/n/5822941.html

相关文章

excel仅复制可见单元格,仅复制筛选后内容

背景 我们经常需要将内容分给不同的人&#xff0c;做完后需要合并 遇到情况如下 那是因为直接选择了整列&#xff0c;当然不可以了。 下面提供几种方法&#xff0c;应该都可以 直接选中要复制区域然后复制&#xff0c;不要选中最上面的列alt;选中可见单元格正常复制&#xff…

【JVM-4】深入解析JVM垃圾回收算法:原理、实现与优化

垃圾回收&#xff08;Garbage Collection, GC&#xff09;是Java虚拟机&#xff08;JVM&#xff09;的核心机制之一&#xff0c;它自动管理堆内存中对象的生命周期&#xff0c;释放不再使用的对象占用的内存空间。理解垃圾回收算法的原理和实现&#xff0c;对于优化Java应用程序…

【前端知识】一款好用的node多版本管理工具nvm

好用的node多版本管理工具nvm 概述一、NVM的主要功能 二、安装NVM二、配置NVM 三、常用命令四、具体应用场景 概述 NVM&#xff08;Node Version Manager&#xff09;是一个用于管理Node.js版本的命令行工具。它允许用户在同一台机器上安装和切换不同版本的Node.js&#xff0c;…

Java算法 数据结构 栈 队列 优先队列 比较器

目录 栈 Stack 性质 构造 方法 代码示例 队列 Queue 性质 构造 方法 代码示例 优先队列 PriorityQueue 性质 构造 方法 代码示例 比较器 1. Comparator 接口的方法 2. 常见的内置比较器 1. 自然排序比较器&#xff08;naturalOrder()&#xff09; 2. 逆序排…

Android ScrollView嵌套X5WebView大片空白问题

scrollview嵌套后webview的高度不可控。留有大片空白。 注&#xff1a;官方不建议scrollview嵌套webview 最好让webview自身滚动 解决方案&#xff1a; act_news_detail_wv.setWebViewClient(new WebViewClient() {Overridepublic void onPageFinished(WebView webView, Str…

HCIP笔记1--IP路由基础回顾、BFD单臂回声、OSPF基础

1. 路由基础回顾 概念 AS(Aotonomous System): 自治系统&#xff0c;由同一机构管理的路由器集合。LAN(Local Area Network): 局域网&#xff0c;用户所使用的网络WAN(Wideless Area Network): 广域网&#xff0c;运营商网络广播域&#xff1a;一个广播帧能在网络中到达的所有…

win32汇编环境,对话框程序中对多行编辑框的操作

;运行效果 ;win32汇编环境,对话框程序中对多行编辑框的操作 ;比如生成多行编辑框&#xff0c;显示文本、获取文本、设置滚动条、捕获超出文本长度消息等。 ;直接抄进RadAsm可编译运行。重点部分加备注。 ;下面为asm文件 ;>>>>>>>>>>>>>…

mobaxterm内置编辑器中文出现乱码如何解决:直接更换编辑器为本地编辑器

诸神缄默不语-个人CSDN博文目录 使用场景是我需要用mobaxterm通过SSH的方式登录服务器&#xff0c;进入服务器之后我就直接打开代码文件&#xff0c;mobaxterm会直接用内置的编辑器&#xff08;MobaTextEditor&#xff09;打开&#xff0c;但这会导致中文编程乱码。 我一开始是…