g2o -- circle_fit代码解析

本文详细介绍了如何使用G2O框架在C++中实现二维圆形的拟合,包括自定义顶点类VertexCircle和边类EdgePointOnCircle,以及如何生成数据、初始化求解器、添加顶点和边并执行优化的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

本文介绍通过g2o框架,拟合二维圆形。其代码逻辑和前一篇的curve_fit相似,可以参照一起看。

代码解析

自定义顶点

/**
 * \brief a circle located at x,y with radius r
 */
class VertexCircle : public g2o::BaseVertex<3, Eigen::Vector3d> { // 顶点包含3个参数
 public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
  VertexCircle() {}

  bool read(std::istream& /*is*/) override { return false; }

  bool write(std::ostream& /*os*/) const override { return false; }

  void setToOriginImpl() override { // 设置顶点的初始值
    cerr << __PRETTY_FUNCTION__ << " not implemented yet" << endl;
  }

  void oplusImpl(const double* update) override { // 增量更新函数
    Eigen::Vector3d::ConstMapType v(update);
    _estimate += v;
  }
};

自定义边

/**
 * \brief measurement for a point on the circle
 *
 * Here the measurement is the point which is on the circle.
 * The error function computes the distance of the point to
 * the center minus the radius of the circle.
 */
class EdgePointOnCircle
    : public g2o::BaseUnaryEdge<1, Eigen::Vector2d, VertexCircle> { // 第一个参数表示是单一顶点的边,第二个参数表示观测值为二维参数,第三个参数表示顶点的类型
 public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  EdgePointOnCircle() {}
  bool read(std::istream& /*is*/) override { return false; }
  bool write(std::ostream& /*os*/) const override { return false; }

  template <typename T>
  bool operator()(const T* circle, T* error) const {
    typename g2o::VectorN<2, T>::ConstMapType center(circle);
    const T& radius = circle[2];

    error[0] = (measurement().cast<T>() - center).norm() - radius; // measurement()表示当前的观测值
    return true;
  }

  G2O_MAKE_AUTO_AD_FUNCTIONS  // use autodiff
};

生成待拟合点

  // generate random data
  Eigen::Vector2d center(4.0, 2.0);
  double radius = 2.0;
  Eigen::Vector2d* points = new Eigen::Vector2d[numPoints];

  g2o::Sampler::seedRand();
  for (int i = 0; i < numPoints; ++i) {
    double r = g2o::Sampler::gaussRand(radius, 0.05); // 模拟偏差
    double angle = g2o::Sampler::uniformRand(0.0, 2.0 * M_PI);
    points[i].x() = center.x() + r * cos(angle);
    points[i].y() = center.y() + r * sin(angle);
  }

初始化求解器

  // setup the solver
  g2o::SparseOptimizer optimizer;
  optimizer.setVerbose(false);

  // allocate the solver
  g2o::OptimizationAlgorithmProperty solverProperty;
  optimizer.setAlgorithm(
      g2o::OptimizationAlgorithmFactory::instance()->construct("lm_dense",
                                                               solverProperty));

添加顶点

  // 1. add the circle vertex
  VertexCircle* circle = new VertexCircle();
  circle->setId(0);
  circle->setEstimate(
      Eigen::Vector3d(3.0, 3.0, 3.0));  // 初始化参数,待优化
  optimizer.addVertex(circle);

添加边

  // 2. add the points we measured
  // 每个待拟合的点都可以形成一条边 
  for (int i = 0; i < numPoints; ++i) {
    EdgePointOnCircle* e = new EdgePointOnCircle;
    e->setInformation(Eigen::Matrix<double, 1, 1>::Identity());
    e->setVertex(0, circle);
    e->setMeasurement(points[i]);
    optimizer.addEdge(e);
  }

启动求解器

  optimizer.initializeOptimization();
  optimizer.setVerbose(verbose);
  optimizer.optimize(maxIterations); // 最大迭代次数

输出结果

  // print out the result
  cout << "Iterative least squares solution" << endl;
  cout << "center of the circle " << circle->estimate().head<2>().transpose()
       << endl;
  cout << "radius of the cirlce " << circle->estimate()(2) << endl;
  cout << "error " << errorOfSolution(numPoints, points, circle->estimate())
       << endl;
  cout << endl;

<think>好的,用户遇到了在加载g2o库时出现未定义符号cs_di_schol的问题,需要解决这个问题。首先,我需要分析可能的原因,并逐步给出解决方案。 首先,用户提到的错误信息是“undefined symbol: cs_di_schol”,这表明在编译或链接过程中,某个共享库(如g2o的Python扩展模块)无法找到符号cs_di_schol。这个符号属于CSparse库中的函数,通常与SuiteSparse相关。因此,可能的原因包括: 1. **CSparse未正确安装**:g2o可能依赖CSparse库,但系统中未安装或安装不正确。 2. **链接路径问题**:编译g2o时,链接器未能正确找到CSparse的库文件。 3. **版本不兼容**:安装的CSparse版本与g2o要求的版本不一致。 4. **编译选项缺失**:在编译g2o时,未正确配置启用CSparse支持的选项。 接下来,我需要根据这些可能的原因,给出对应的解决方案步骤。首先检查CSparse是否安装,然后确认编译时的链接选项,确保版本兼容性,并重新安装或配置环境。 另外,参考用户提供的引用内容,例如引用[4]中提到的TypeMeta错误是由于依赖版本不匹配,类似的问题可能出现在这里。可能需要用户检查g2o和CSparse的版本是否兼容,并确保在编译g2o时正确链接到CSparse库。 可能的解决步骤包括: - 安装SuiteSparse和CSparse开发包。 - 确认环境变量如LD_LIBRARY_PATH包含CSparse的库路径。 - 重新编译g2o并确保链接到正确的库。 - 使用符号链接修复库路径问题。 此外,用户可能需要使用ldd或nm工具检查共享库的依赖关系,确认cs_di_schol是否存在于链接的库中。如果编译时未正确链接,可能需要调整CMake参数,添加CSparse的包含路径和库路径。 最后,生成相关问题,帮助用户进一步排查类似问题。</think>### 解决g2o库加载时出现`undefined symbol: cs_di_schol`的问题 #### 问题分析 错误`undefined symbol: cs_di_schol`表明系统在加载g2o的动态链接库(如`.cpython-38-x86_64-linux-gnu.so`)时,未能找到符号`cs_di_schol`。该符号属于**CSparse**库(SuiteSparse的一部分),常见原因如下: 1. **缺少CSparse依赖**:g2o依赖SuiteSparse中的CSparse组件,但未正确安装或链接。 2. **链接路径错误**:编译g2o时未正确指定CSparse库路径,导致符号未绑定。 3. **版本不兼容**:安装的CSparse版本与g2o编译时使用的版本不一致[^4]。 --- #### 解决方案步骤 1. **安装SuiteSparse和CSparse** - 在Ubuntu/Debian中: ```bash sudo apt-get install libsuitesparse-dev ``` - 验证安装:检查是否存在文件`/usr/include/umfpack.h`和`/usr/lib/x86_64-linux-gnu/libcxsparse.so`。 2. **检查动态库路径** - 确保CSparse库路径(如`/usr/lib/x86_64-linux-gnu`)包含在`LD_LIBRARY_PATH`中: ```bash export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH ``` 3. **重新编译g2o并链接CSparse** - 若从源码编译g2o,需在CMake配置中显式启用CSparse支持: ```bash cmake -DBUILD_WITH_MARCH_NATIVE=ON \ -DG2O_USE_CHOLMOD=OFF \ -DG2O_USE_CSPARSE=ON \ -DCSPARSE_INCLUDE_DIR=/usr/include/suitesparse \ -DCSPARSE_LIBRARY=/usr/lib/x86_64-linux-gnu/libcxsparse.so ``` - 编译后重新安装: ```bash make -j$(nproc) sudo make install ``` 4. **修复符号链接(可选)** - 若CSparse库文件命名不规范(如版本后缀冲突),手动创建符号链接: ```bash sudo ln -s /usr/lib/x86_64-linux-gnu/libcxsparse.so.3 /usr/lib/x86_64-linux-gnu/libcxsparse.so ``` 5. **验证解决方案** - 使用`ldd`检查g2o库的依赖关系: ```bash ldd /path/to/g2o/_ext.cpython-38-x86_64-linux-gnu.so | grep "libcxsparse" ``` - 若输出包含`libcxsparse.so`,则链接成功。 --- #### 示例操作流程 ```bash # 安装依赖 sudo apt-get install libsuitesparse-dev # 设置环境变量 export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH # 重新编译g2o cd /path/to/g2o/build rm -rf * cmake -DG2O_USE_CSPARSE=ON .. make sudo make install ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值