SLAM中的非线性优-3D图优化之四元数在Opencv-PNP中的应用(五)

之前章节总结了轴角以及李群李代数参数化,简单介绍了下四元数参数化,本节补充下四元数表示的位姿,如何利用视觉3D到2D重投影误差的残差及雅可比,完整代码如下

https://gitee.com/zl_vslam/slam_optimizer/blob/master/3d_optimize/ch5/pose_estimation_3d2d.cpphttps://gitee.com/zl_vslam/slam_optimizer/blob/master/3d_optimize/ch5/pose_estimation_3d2d.cpp

结果展示

复制代码
    bool Solve(const std::vector<Eigen::Vector3d>& landmarks,
               const std::vector<Eigen::Vector2d>& bearings,
               Eigen::Vector3d& initial_translation,
               Eigen::Quaterniond& initial_rotation) {
        
        if (landmarks.size() != bearings.size() || landmarks.empty()) {
            std::cerr << "Error: landmarks and bearings must have same non-zero size" << std::endl;
            return false;
        }
        
        // 将初始旋转转换为四元数(确保是单位四元数)
        Eigen::Quaterniond q = initial_rotation.normalized();
        
        // 优化变量
        double translation[3] = {initial_translation.x(), initial_translation.y(), initial_translation.z()};
        double quaternion[4] = {q.x(), q.y(), q.z(), q.w()}; // Eigen使用 [x,y,z,w] 格式
        
        // 创建问题
        ceres::Problem problem;
        
        // 添加四元数流形约束
        QuaternionManifold* quaternion_manifold = new QuaternionManifold();
        problem.AddParameterBlock(quaternion, 4, quaternion_manifold);
        
        // 为每个观测添加残差块(使用解析导数)
        for (size_t i = 0; i < landmarks.size(); ++i) {
            ceres::CostFunction* cost_function = 
                new AnalyticReprojectionError(landmarks[i], bearings[i], fx_, fy_, cx_, cy_);
            
            problem.AddResidualBlock(cost_function, 
                                   nullptr, // 使用默认的损失函数(L2范数)
                                   translation, 
                                   quaternion);
        }
        
        // 设置求解选项
        ceres::Solver::Options options;
        
        options.linear_solver_type = ceres::DENSE_QR;
        options.minimizer_progress_to_stdout = true;
        options.max_num_iterations = 100;
        options.function_tolerance = 1e-10;
        options.gradient_tolerance = 1e-10;
        options.parameter_tolerance = 1e-10;

        // 暂时禁用梯度检查以测试基本功能
        // options.check_gradients = false;
        // options.gradient_check_relative_precision = 1e-6;

        // 使用更保守的优化策略
        // options.trust_region_strategy_type = ceres::DOGLEG;

        // 求解
        ceres::Solver::Summary summary;
        ceres::Solve(options, &problem, &summary);
        
        std::cout << summary.BriefReport() << std::endl;

        std::cout << "Initial cost: " << summary.initial_cost << std::endl;
        std::cout << "Final cost: " << summary.final_cost << std::endl;
        
        // 输出优化结果
        if (summary.IsSolutionUsable()) {
            // 更新结果
            initial_translation = Eigen::Vector3d(translation[0], translation[1], translation[2]);
            
            // 注意:Eigen四元数构造函数的参数顺序是 (w, x, y, z)
            initial_rotation = Eigen::Quaterniond(quaternion[3], quaternion[0], quaternion[1], quaternion[2]);
            initial_rotation.normalize();
            
            std::cout << "Optimization successful!" << std::endl;
            std::cout << "Final translation: " << initial_translation.transpose() << std::endl;
            std::cout << "Final rotation quaternion: " << initial_rotation.coeffs().transpose() << std::endl;
            
            // 计算旋转矩阵和欧拉角(可选)
            Eigen::Matrix3d R_final = initial_rotation.toRotationMatrix();
            std::cout << "Final rotation matrix:\n" << R_final << std::endl;
            
            return true;
        } else {
            std::cerr << "Optimization failed!" << std::endl;
            return false;
        }
    }

主流程如上所示,主要就是利用四元数求的导数,来优化pnp的位姿,结果如下

从图中可以看到迭代了38次后收敛了,相对于opencv的结果,差别也不大了,足以证明算法没有问题

相关推荐
专业程序开发源几秒前
flask家电故障预测系统92491-计算机课程设计/毕业设计
vscode·python·sql·算法·flask·课程设计
不开大的凯20774 分钟前
AI权力游戏:同一天,两种答案,一场算力暗战
大数据·人工智能·ai·ai office
零基础1236 分钟前
自动驾驶中的边界情况处理:基于世界模型与混合专家及大语言模型的方法
人工智能·语言模型·自动驾驶
Logic1019 分钟前
C语言/数据结构欧几里得算法题解:长方形切割最大正方形——贪心划分计数
c语言·数据结构·算法·贪心算法·时间复杂度·空间复杂度·欧几里得算法
DongQiShanRen13 分钟前
玄龙(上):TICK 主循环——意识心跳怎么跳
linux·jvm·数据库·人工智能·数据挖掘·rust
研來如此22 分钟前
OpenCV官方下载界面下载opencv库
人工智能·opencv·计算机视觉
yi01125 分钟前
LeetCode 643. 子数组最大平均数 I|从暴力枚举到滑动窗口
人工智能·笔记·python·算法·leetcode·滑动窗口
天远API28 分钟前
零信任架构实战:基于天远风控经营异常预警构建自动化供应商店铺巡检网关
人工智能·架构·自动化·dubbo
田里的水稻36 分钟前
EP_ROS框架---相机视频流交互二
人工智能·深度学习·数码相机·机器学习·迁移学习