ceres学习之平面拟合

背景:orb-slam2最终保存的轨迹形成的平面是一个倾斜的,这个与相机初始化位置有关,但是有些时候,我们需要的是一个2d的轨迹的试图,直接将轨迹向某一个平面投影的话。

得到的估计是失真的,所以我们需要对轨迹的location数据进行处理,就是首先拟合出轨迹的平面,然后将这个平面绕着一个轴,旋转一定的角度,将其旋转成与某一个做表面平行,

然后再取出其中两个维度的坐标,那么我们就可以得到一个真是的2d平面。为实现上面的目的,第一步工作就是要根据输入的坐标数据,3d坐标点,拟合出一个主平面,使用ceres

优化求解平面的四个参数a,b,c,d的值。这个过程主要是熟悉使用ceres优化特定问题的一个框架,然后根据实际的问题,去填入具体的残差函数,等。

planeFitting.h

#include <iostream>
#include <ceres/ceres.h>
#include <ceres/rotation.h>

struct OptimalPlanFitting
{
    
	OptimalPlanFitting(double x, double y, double z):x_(x), y_(y), z_(z)
	{
	}
    
	template<typename T>
	bool operator()(const T* const a, 
                    const T* const b, 
                    const T* const c, 
                    const T* const d,
                    T* residual)const
	{
        T temp = a[0]*x_ + b[0]*y_ + c[0]*z_ + d[0];
       
        residual[0] = temp*temp/(a[0]*a[0] + b[0]*b[0] + c[0]*c[0]);
		
		return true;

	}

	static ceres::CostFunction* cost(double x, double y, double z)
	{
		return(new ceres::AutoDiffCostFunction<OptimalPlanFitting, 1, 1, 1, 1, 1>(new OptimalPlanFitting(x, y, z)));
	}
private:
    const double x_;
    const double y_;
    const double z_;

};

planeFitting.cpp

#include <iostream>
#include <ceres/ceres.h>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include <string>
#include <fstream>
#include "planeFitting.h"
using namespace std;
using namespace ceres;


int split(std::string str, std::string pattern, std::vector<std::string> &words)
{
    std::string::size_type pos;
    std::string word;
    int num = 0;
    str += pattern;
    std::string::size_type size = str.size();
    for (auto i = 0; i < size; i++)
    {
        pos = str.find(pattern, i);
        if (pos == i)
        {
            continue;//if first string is pattern
        }
        if (pos < size)
        {
            word = str.substr(i, pos - i);
            words.push_back(word);
            i = pos + pattern.size() - 1;
            num++;
        }
    }
    return num;
}
void readFile(std::string filePath, std::vector<Eigen::Vector3d>& locations)
{
    ifstream infile;
    infile.open(filePath);
    if(!infile)
    {
        std::cout<<"filed to load trajectory data"<<std::endl;
        return;
    }
    string str;
    std::vector<string> words;
    
    while(!infile.eof())
    {
        words.clear();
        std::getline(infile, str);
        split(str, " ", words);
        Eigen::Vector3d position(atof(const_cast<const char *>(words[1].c_str())),
                                 atof(const_cast<const char *>(words[2].c_str())),
                                 atof(const_cast<const char *>(words[3].c_str())));
        locations.push_back(position);    
    }
}
//这边传参数,要使用double 类型
//double *params或者是这样
int planFittingOptimal(std::vector<Eigen::Vector3d> locations, double params[4])
{
    //double params[4]={1.0,0.1,0.1,0.2};
    ceres::Problem problem;
    for(int i = 0; i<locations.size(); i++)
    {
        Eigen::Vector3d loc = locations[i];
        //std::cout<<loc<<std::endl;
        ceres::CostFunction *cost_func = OptimalPlanFitting::cost(loc.x(), loc.y(), loc.z());
        problem.AddResidualBlock(cost_func, new ceres::HuberLoss(1.0), &params[0], &params[1], &params[2], &params[3]);
    }
    ceres::Solver::Options options;
    options.linear_solver_type = ceres::SPARSE_SCHUR;
    options.trust_region_strategy_type = ceres::LEVENBERG_MARQUARDT;
    options.max_num_iterations = 50;
    options.minimizer_progress_to_stdout = true;

    ceres::Solver::Summary summary;
    ceres::Solve(options, &problem, &summary);
    std::cout<<summary.BriefReport()<<"\n";

    std::cout<<"a: "<<params[0]<<" \nb:"<<params[1]<<" \nc:"<<params[2]<<"\nd:"<<params[3]<<std::endl;


}
int main()
{
    double params[4]={1.0,0.1,0.2,0.1};

    std::string filePath = "/home/yunlei/COOL/ceres-study/data/CameraTrajectory_common.txt";
    std::vector<Eigen::Vector3d> locations;
    readFile(filePath, locations);
    //std::cout<<"locations.size(): "<<locations.size()<<std::endl;
    planFittingOptimal(locations, params);

    std::cout<<params[0]<<" "<<params[1]<<" "<<params[2]<<" "<<params[3]<<std::endl;
    return 0;
}

 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值