Bundle Adjustment 相关源码分析

本文为原创博客,转载请注明出处:https://blog.youkuaiyun.com/q_z_r_s

机器感知
一个专注于SLAM、三维重建、机器视觉等相关技术文章分享的公众号
公众号:机器感知
  • Vertex成员变量类型分析

    Vertex: public BaseVertex<D, T>
    //base_vertex.h::
    template <int D, typename T>
    class BaseVertex : public OptimizableGraph::Vertex {
        public:
        typedef T EstimateType;
        ...
        EstimateType _estimate;    
    };
    //由此可知,_estimate的类型为T
    
  • Edge成员变量分析

    Edge: public BaseBinaryEdge<D, E, Xi, Xj>
    //base_binary_edge.h::
    template <int D, typename E, typename VertexXi, typename VertexXj>
    class BaseBinaryEdge : public BaseEdge<D, E>
    //base_edge.h::
     template <int D, typename E>
    class BaseEdge : public OptimizableGraph::Edge {
        typedef E Measurement;
        typedef Eigen::Matrix<double, D, 1, Eigen::ColMajor> ErrorVector;
        ...
        Measurement _measurement;
        ErrorVector _error;
    };
    //由此可知,_error的类型为Matrix<double, D, 1>,_measurement的类型为E
    
  • SE3Quat 成员变量

    //SE3Quat实际上是7维的,而派生VertexSE3Expmap时确实6维的
    Eigen::Quaterniond _r;
    Vector3D _t;
    
  • SE3Quat 核心构造函数

    SE3Quat();//_r初始化为单位阵,_t初始化为0
    //用旋转矩阵R和平移向量t来初始化_r、_t
    SE3Quat(const Matrix3D& R, const Vector3D& t):_r(Eigen::Quaterniond(R)),_t(t)
    //用四元数q和平移向量t来初始化_r、_t
    SE3Quat(const Eigen::Quaterniond& q, const Vector3D& t):_r(q),_t(t)
    
  • SE3Quat 核心成员函数

    Vector6d log()//返回SE(3)对应的李代数
    Vector3D map(const Vector3D & xyz)//根据类中_r和_t给出xyz映射后的坐标
    static SE3Quat exp(const Vector6d & update) {//与log相反,返回李代数对应的SE3Quat
    	Vector3D omega;//旋转:角轴
        for (int i=0; i<3; i++)
            omega[i]=update[i];
        Vector3D upsilon;//平移
        for (int i=0; i<3; i++)
            upsilon[i]=update[i+3];
        double theta = omega.norm();
        Matrix3D Omega = skew(omega);
        Matrix3D R;
        Matrix3D V;
        if (theta<0.00001)
        {
            //TODO: CHECK WHETHER THIS IS CORRECT!!!
            R = (Matrix3D::Identity() + Omega + Omega*Omega);
            V = R;
        }
        else
        {
            Matrix3D Omega2 = Omega*Omega;
            R = (Matrix3D::Identity()
                 + sin(theta)/theta *Omega
                 + (1-cos(theta))/(theta*theta)*Omega2);
            V = (Matrix3D::Identity()
                 + (1-cos(theta))/(theta*theta)*Omega
                 + (theta-sin(theta))/(pow(theta,3))*Omega2);
        }
        return SE3Quat(Eigen::Quaterniond(R),V*upsilon);
    }
    //重载*运算符,在types_six_dof_example.h::VertexSE3Expmap::oplusImpl中使用
    inline SE3Quat operator* (const SE3Quat& tr2) const{
        SE3Quat result(*this);
        result._t += _r*tr2._t;
        result._r*=tr2._r;
        result.normalizeRotation();
        return result;
    }
    //重载输出流<<操作符
    inline std::ostream& operator <<(std::ostream& out_str, const SE3Quat& se3)
    {
        out_str << se3.to_homogeneous_matrix()  << std::endl;
        return out_str;
    }
    
  • VertexSBAPointXYZ

    class G2O_TYPES_SBA_API VertexSBAPointXYZ : public BaseVertex<3, Vector3D> {
    public:
        ...
    	virtual void setToOriginImpl() {
          _estimate.fill(0.);
        }
        virtual void oplusImpl(const double* update)
        {
          Eigen::Map<const Vector3D> v(update);
          //XYZ为R(3)空间,可以直接进行相加
          _estimate += v;
        }
    };
    
  • VertexSE3Expmap

    class G2O_TYPES_SBA_API VertexSE3Expmap : public BaseVertex<6, SE3Quat> {
    public:
        ...
        virtual void setToOriginImpl() {
            //通过上面的分析可以知道_estimate为SE3Quat类型,使用默认初始化函数
            _estimate = SE3Quat();
        }
        virtual void oplusImpl(const double* update_)  {
            Eigen::Map<const Vector6d> update(update_);
            //首先使用SE3Quat静态成员函数exp(指数映射)把Vector6D转化为SE3Quat类中的_r和_t
            setEstimate(SE3Quat::exp(update)*estimate());
        }
    };
    
  • EdgeProjectXYZ2UV

    class G2O_TYPES_SBA_API EdgeProjectXYZ2UV : public  BaseBinaryEdge<2, Vector2D, VertexSBAPointXYZ, VertexSE3Expmap> {
    public:
        ....
        void computeError()  {
          //在世界坐标系中的相机位姿
          const VertexSE3Expmap* v1 = static_cast<const VertexSE3Expmap*>(_vertices[1]);
          const VertexSBAPointXYZ* v2 = static_cast<const VertexSBAPointXYZ*>
              (_vertices[0]);//世界坐标系3D点坐标
          const CameraParameters * cam//相机内参
              = static_cast<const CameraParameters*>(parameter(0));
          Vector2D obs(_measurement);//观测值,这里为特征点像素坐标(u,v)
          //观测值-重投影值(相机内参映射(位姿映射(3D点坐标)))
          _error = obs-cam->cam_map(v1->estimate().map(v2->estimate()));
        }
        virtual void linearizeOplus();
        CameraParameters * _cam;
    };
    
<think>嗯,用户提供的日志信息显示他们在运行某个使用Ceres库进行全局定位的程序时遇到了问题。具体来说,日志中的警告信息指出虽然用户请求使用GPU进行光束法平差(bundle adjustment),但Ceres在编译时没有CUDA和cuDNN的支持,因此回退到使用CPU的稠密和稀疏求解器。这可能会影响性能,尤其是在处理大规模问题时。 首先,我需要确认用户的主要需求是什么。他们可能希望利用GPU加速来提高计算效率,但目前无法实现。因此,解决方案可能涉及重新编译Ceres库以包含CUDA支持,或者检查现有的安装是否正确配置了GPU依赖项。 接下来,我需要考虑用户可能的背景。他们可能是在使用某个SLAM或三维重建相关的软件,比如COLMAP或其他计算机视觉工具,这些工具通常依赖Ceres进行优化。用户可能对Ceres的配置和编译不太熟悉,需要指导如何正确安装和配置带有CUDA支持的Ceres。 然后,我需要分析可能的原因。首先,Ceres的版本可能较旧,不支持CUDA。其次,编译Ceres时可能没有正确安装CUDA工具包或cuDNN库,导致未启用GPU支持。另外,用户可能没有正确设置编译选项,例如未指定启用CUDA的标志。 针对这些问题,解决步骤可能包括:更新Ceres到支持CUDA的版本,安装必要的CUDA和cuDNN依赖,重新编译Ceres时启用CUDA支持,或者使用预编译的支持GPU的库。此外,还需要验证安装是否成功,可以通过运行示例程序或检查日志中的信息来确认。 用户可能还关心如何验证安装是否正确,或者是否有其他替代方案。例如,使用其他支持GPU的优化库,或者调整程序以避免需要GPU加速的部分。此外,用户可能遇到其他相关问题,比如驱动版本不兼容或CUDA安装错误,需要进一步的排查步骤。 最后,我需要确保提供的解决方案清晰且分步骤,涵盖从检查依赖到重新编译的全过程,同时提供验证方法和可能的替代方案。还要考虑用户可能的操作系统环境(如Linux或Windows),并给出相应的指导,因为不同系统的安装步骤可能不同。</think>该日志表明程序尝试使用GPU加速光束法平差(Bundle Adjustment),但Ceres库未编译CUDA支持,导致回退到CPU模式。以下是分析和解决方案: --- ### **原因分析** 1. **Ceres未启用CUDA支持** - 编译Ceres时未检测到CUDA/cuDNN环境,或未开启相关选项。 - 当前Ceres版本可能不支持GPU加速(需v2.1.0+)。 2. **依赖缺失** - 系统未安装CUDA工具包、cuDNN库或NVIDIA驱动。 - Ceres依赖的线性代数库(如Eigen)未启用GPU支持。 3. **硬件限制** - GPU型号不支持CUDA或显存不足。 --- ### **解决方案** #### 1. **安装CUDA/cuDNN依赖** - **Linux**(以Ubuntu为例): ```bash # 安装CUDA工具包(需与驱动版本匹配) sudo apt install nvidia-cuda-toolkit # 安装cuDNN(需注册NVIDIA开发者账号) sudo apt install libcudnn8 ``` - **Windows**: 下载并安装对应显卡驱动的[CUDA Toolkit](https://developer.nvidia.com/cuda-downloads)和cuDNN。 #### 2. **重新编译Ceres with CUDA支持** ```bash # 克隆Ceres源码(需v2.1.0+) git clone https://ceres-solver.googlesource.com/ceres-solver cd ceres-solver mkdir build && cd build # 配置编译选项(启用CUDA) cmake .. -DBUILD_EXAMPLES=ON \ -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda \ -DWITH_CUDA=ON \ -DUSE_OPENMP=ON # 可选:启用多线程 # 编译并安装 make -j$(nproc) sudo make install ``` #### 3. **验证CUDA支持** - 运行Ceres提供的CUDA测试用例: ```bash # 检查是否启用CUDA ./bin/simple_bundle_adjuster --use_gpu # 若输出含"Using Cuda"则成功 ``` #### 4. **使用预编译库(替代方案)** - **Linux**(通过Conda): ```bash conda install -c conda-forge ceres-solver ``` - **Windows**: 使用[vcpkg](https://github.com/microsoft/vcpkg)安装支持CUDA的Ceres: ```bash vcpkg install ceres-solver[cuda] ``` --- ### **替代方案** 1. **改用CPU模式** - 调整程序参数禁用GPU(如删除`--use_gpu`标志),性能可能下降但功能不受影响。 2. **更换优化库** - 使用支持GPU加速的替代库,如[PyTorch3D](https://github.com/facebookresearch/pytorch3d)或[Open3D](http://www.open3d.org/)。 --- ### **验证步骤** 1. 检查Ceres版本: ```bash pkg-config --modversion ceres # 需≥2.1.0 ``` 2. 查看编译日志是否包含CUDA支持: ```bash grep -i cuda CMakeCache.txt # 应显示路径如`CUDA_TOOLKIT_ROOT_DIR:PATH=/usr/local/cuda` ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值