• gtsam OrientedPlane3及OrientedPlane3Factor的使用


    一、OrientedPlane3
    构造函数是来自平面的方程系数:ax+by+cz+d=0的(a,b,c,d)
    是有方向的。

    比如一个平面,平行与xoz平面,在xoy平面的投影线段与x轴平行,处于y轴上方2处,这个平面的法向量可以是(0,1,0):方向指向y轴正方向,也可以是(0,-1,0),方向指向y轴负方向。具体定哪个,要看自己的使用需求。
    不同的法向量,得出不同的参数d,比如第一个,其参数d=-2,第二个则是2。
    即d的正负号,取决于原点在法向量的那一侧。

    二、OrientedPlane3Factor
    这个factor,用来描述从某个位姿观察到的一个平面,约束涉及的变量就是pose、plane,约束内容就是这个pose观察到的这个平面的方程。

    构造函数的说明:
    在这个pose下的平面方程的系数,而不是全局坐标系下的系数。

    三、测试
    在这里插入图片描述

    using symbol_shorthand::X;
    using symbol_shorthand::P;
    
    void test_room_plane(){
        OrientedPlane3 p1(0,1,0,0);
        OrientedPlane3 p2(0,-1,0,1);
        OrientedPlane3 p3(-1,0,0,4);
    
        OrientedPlane3 p4(1,0,0,-3);
        OrientedPlane3 p5(0,1,0,-2);
        OrientedPlane3 p6(1,0,0,-2);
    
        OrientedPlane3 p7(0,-1,0,3);
        OrientedPlane3 p8(0,1,0,-2);
        OrientedPlane3 p9(-1,0,0,5);
    
        std::vector<OrientedPlane3> planes={p1,p2,p3,p4,p5,p6,p7,p8,p9};
    
        //朝x轴正方向
        gtsam::Pose3 pose1(gtsam::Rot3::Ypr(0.0, 0.0, 0.0), Point3(0.0, 0.5, 0.0));
        gtsam::Pose3 pose2(gtsam::Rot3::Ypr(0.0, 0.0, 0.0), Point3(0.5, 0.5, 0.0));
        gtsam::Pose3 pose3(gtsam::Rot3::Ypr(0.0, 0.0, 0.0), Point3(1, 0.5, 0.0));
        gtsam::Pose3 pose4(gtsam::Rot3::Ypr(0.0, 0.0, 0.0), Point3(1.5, 0.5, 0.0));
        gtsam::Pose3 pose5(gtsam::Rot3::Ypr(0.0, 0.0, 0.0), Point3(2, 0.5, 0.0));
        gtsam::Pose3 pose6(gtsam::Rot3::Ypr(0.0, 0.0, 0.0), Point3(2.5, 0.5, 0.0));
        gtsam::Pose3 pose7(gtsam::Rot3::Ypr(0.0, 0.0, 0.0), Point3(3, 0.5, 0.0));
        gtsam::Pose3 pose8(gtsam::Rot3::Ypr(0.0, 0.0, 0.0), Point3(3.5, 0.5, 0.0));
    
        //朝y轴正方向
        gtsam::Pose3 pose9(gtsam::Rot3::Ypr(M_PI/2, 0.0, 0.0), Point3(3.5, 0.5, 0.0));
        gtsam::Pose3 pose10(gtsam::Rot3::Ypr(M_PI/2, 0.0, 0.0), Point3(3.5, 1, 0.0));
        gtsam::Pose3 pose11(gtsam::Rot3::Ypr(M_PI/2, 0.0, 0.0), Point3(3.5, 1.5, 0.0));
        gtsam::Pose3 pose12(gtsam::Rot3::Ypr(M_PI/2, 0.0, 0.0), Point3(3.5, 2, 0.0));
        gtsam::Pose3 pose13(gtsam::Rot3::Ypr(M_PI/2, 0.0, 0.0), Point3(3.5, 2.5, 0.0));
    
        //朝x轴正方向
        gtsam::Pose3 pose14(gtsam::Rot3::Ypr(0, 0.0, 0.0), Point3(3.5, 2.5, 0.0));
        gtsam::Pose3 pose15(gtsam::Rot3::Ypr(0, 0.0, 0.0), Point3(4, 2.5, 0.0));
        gtsam::Pose3 pose16(gtsam::Rot3::Ypr(0, 0.0, 0.0), Point3(4.5, 2.5, 0.0));
        gtsam::Pose3 pose17(gtsam::Rot3::Ypr(0, 0.0, 0.0), Point3(5, 2.5, 0.0));
    
        std::vector<gtsam::Pose3> poses={pose1,
                                            pose2,
                                            pose3,
                                            pose4,
                                            pose5,
                                            pose6,
                                            pose7,
                                            pose8,
                                            pose9,
                                            pose10,
                                            pose11,
                                            pose12,
                                            pose13,
                                            pose14,
                                            pose15,
                                            pose16,
                                            pose17};
    
        //simple check
        auto p4_loc=p4.transform(pose9);
        pose9.print("pose9");
        p4.print("p4");
        p4_loc.print("p4_loc");
    
    
        //观测数据关联
        std::map<int,std::vector<int>> pose_id_to_plane_ids;//全部都加了1
        for(int i=1;i<9;i++){
            pose_id_to_plane_ids[i]={1,2,3};
        }
        for(int i=9;i<11;i++){
            pose_id_to_plane_ids[i]={1,3,4};
        }
        for(int i=11;i<13;i++){
            pose_id_to_plane_ids[i]={5,6,7};
        }
        for(int i=13;i<17;i++){
            pose_id_to_plane_ids[i]={6,7,8,9};
        }
    
    
        //构建factor
        gtsam::NonlinearFactorGraph graph;
        Values initialEstimate;
    
        Pose3 delta(Rot3::Ypr(0.0,0.0,0.0),Point3(0.05,-0.10,0.20));
        const auto x_p_noise = noiseModel::Isotropic::Sigma(3, 0.001);
        gtsam::Vector6 sigmas;
        sigmas<<0.3,0.3,0.3,0.1,0.1,0.1;
        auto pose_noise=noiseModel::Diagonal::Sigmas(sigmas);
    
        for(auto iter=pose_id_to_plane_ids.begin();iter!=pose_id_to_plane_ids.end();iter++){
            int pose_id=iter->first-1;
            std::vector<int> pids=iter->second;
            gtsam::Pose3 po=poses[pose_id];
    
            //pose加入噪声
    
            //pose加入graph先验
            graph.emplace_shared<PriorFactor<Pose3>>(X(pose_id), po, pose_noise);
            initialEstimate.insert(X(pose_id), po);
    
            //转换到pose的相对观测
            for(auto pid:pids){
                int planid=pid-1;
    
                auto pn=planes[planid];
                auto related_plane=pn.transform(po);
    
                //orientedplane factor
                Vector4 z=related_plane.planeCoefficients();
                OrientedPlane3Factor opf(z,x_p_noise,X(pose_id),P(planid));
    
                graph.add(opf);
    
                if(!initialEstimate.exists(P(planid))){
                    initialEstimate.insert(P(planid),pn);
                }
            }   
        }
    
    
    
        GaussNewtonParams params;
        // params.setVerbosity("ERROR");
        params.setMaxIterations(20);
        params.setRelativeErrorTol(-std::numeric_limits<double>::max());
        // params.setErrorTol(-std::numeric_limits::max());
        params.setAbsoluteErrorTol(-std::numeric_limits<double>::max());
    
        Values result = GaussNewtonOptimizer(graph, initialEstimate, params).optimize();
    
        std::cout<<"\n\n--------optimized result-----------------\n";
        for(int i=0;i<poses.size();i++){
            if(result.exists(X(i))){
                // std::cout<<"pose"<
                std::string n="pose"+std::to_string(i+1);
                // result.at(X(i)).print(n);
                auto op=result.at<Pose3>(X(i));
                std::cout<<n<<": \nypr="<<op.rotation().ypr().transpose()<<"\npos="<<op.translation().transpose()<<std::endl;
                std::cout<<"\tdiff ypr="<<(op.rotation().ypr()-poses[i].rotation().ypr()).transpose()<<"\n"
                <<"\tdiff pos ="<<(op.translation()-poses[i].translation()).transpose()<<"\n";
                std::cout<<"\n";
            }
        }
        std::cout<<"\n\n";
        for(int i=0;i<planes.size();i++){
            if(result.exists(P(i))){
                // std::cout<<"pose"<
                std::string n="plane"+std::to_string(i+1)+"\n";
                auto op=result.at<OrientedPlane3>(P(i));
                result.at(P(i)).print(n);
                std::cout<<"diff coeff = "<<(op.planeCoefficients()-planes[i].planeCoefficients()).transpose()<<std::endl;
                std::cout<<"\n";
            }
        }
    
    }
    
  • 相关阅读:
    JavaScript设计模式之装饰器模式
    程序无法启动,提示“找不到msvcp140.dll”或“msvcp140.dll缺失报错”解决方法
    按关键字搜索淘宝商品 API 返回值说明
    MySQL数据库管理基本操作(一)
    【牛客-算法】NC38 螺旋矩阵
    React中memo()、useCallback()、useMemo() 区别使用详解
    Leetcode 93. Restore IP Addresses
    力扣日记3.11-【贪心算法篇】455. 分发饼干
    洛谷P4185 离线+并查集
    notepad++ 批量替换删除指定字符之后 或者 之前的字符,Notepad+批量替换使用大全
  • 原文地址:https://blog.csdn.net/brightming/article/details/127067681