源码阅读,能力有限,如有某处理解错误,请指出,谢谢。
optimize.hpp:主要是利用ceres完成非线性优化,但是在这个cpp中只有代价函数的构造和残差的定义,以及使用自动求导,没有针对一个具体的问题展开求解
残差定义:residual=normal/transform-average
使用 Ceres Solver 求解非线性优化问题,主要包括以下几部分:
- 【STEP 1】构建优化问题(ceres::Problem)
- 【STEP 2】构建代价函数(ceres::CostFunction) 或残差(residual)
- 【STEP 3】配置代价函数和损失函数(ceres::Problem::AddResidualBlock):通过 AddResidualBlock 添加代价函数(cost function)、损失函数(loss function) 和待优化状态量
- 【STEP 4】配置求解器(ceres::Solver::Options)
- 【STEP 5】运行求解器(ceres::Solve(options, &problem, &summary))
#pragma once
#include "ceres/ceres.h"
#include "ceres/rotation.h"
#include <eigen3/Eigen/Dense>
#include <math.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
定义BalmVoxelEnergy1类,实现的功能:构造一个代价函数,定义残差,利用ceres的自动求导
struct BalmVoxelEnergy1 {
//构造函数,传入参数,并完成传递
BalmVoxelEnergy1(const Eigen::Vector3d ¤t_laser_point,
const Eigen::Vector3d &point_average,
const Eigen::Vector3d &normal,
const Eigen::Matrix4d &imu_tran)
: current_laser_point_(current_laser_point),
point_average_(point_average), normal_(normal), imu_tran_(imu_tran) {}
//析构函数
~BalmVoxelEnergy1() {}
//ceres代价函数需要用模板构造仿函数实现
template <typename T>
bool operator()(const T *const q, const T *const t, T *residual) const {
T cur_p[3];
cur_p[0] = T(current_laser_point_(0));
cur_p[1] = T(current_laser_point_(1));
cur_p[2] = T(current_laser_point_(2));
T world_p[3];
//给出旋转向量q,由cur_p得到world_p
ceres::QuaternionRotatePoint(q, cur_p, world_p);
// ceres::AngleAxisRotatePoint(q, cur_p, world_p);
//加上平移向量,得到完整的世界坐标系下的坐标
world_p[0] += t[0];
world_p[1] += t[1];
// world_p[2] += t[2];
T tran_p[3];
// n * (p - p_aver)
//定义一个残差
tran_p[0] = imu_tran_(0, 0) * world_p[0] + imu_tran_(0, 1) * world_p[1] +
imu_tran_(0, 2) * world_p[2] + imu_tran_(0, 3) -
point_average_[0];
tran_p[1] = imu_tran_(1, 0) * world_p[0] + imu_tran_(1, 1) * world_p[1] +
imu_tran_(1, 2) * world_p[2] + imu_tran_(1, 3) -
point_average_[1];
tran_p[2] = imu_tran_(2, 0) * world_p[0] + imu_tran_(2, 1) * world_p[1] +
imu_tran_(2, 2) * world_p[2] + imu_tran_(2, 3) -
point_average_[2];
residual[0] = normal_[0] * tran_p[0] + normal_[1] * tran_p[1] +
normal_[2] * tran_p[2];
return true;
}
static ceres::CostFunction *Create(const Eigen::Vector3d ¤t_laser_point,
const Eigen::Vector3d &point_average,
const Eigen::Vector3d &normal,
const Eigen::Matrix4d &imu_tran) {
//使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个是输入维度,即待寻优参数x的维度
auto cost_function =
new ceres::AutoDiffCostFunction<BalmVoxelEnergy1, 1, 4, 3>(
new BalmVoxelEnergy1(current_laser_point, point_average, normal,
imu_tran));
return cost_function;
}
const Eigen::Vector3d current_laser_point_;
const Eigen::Vector3d point_average_;
const Eigen::Vector3d normal_;
const Eigen::Matrix4d imu_tran_;
};
定义BalmVoxelEnergy2类,实现的功能:构造一个代价函数,定义残差,利用ceres的自动求导
struct BalmVoxelEnergy2 {
//构造函数,传入参数,并完成传递
BalmVoxelEnergy2(const Eigen::Vector3d ¤t_laser_point,
const Eigen::Vector3d &point_average,
const Eigen::Vector3d &normal,
const Eigen::Matrix4d &imu_tran,
const Eigen::Matrix4d &imu_tran_orig)
: current_laser_point_(current_laser_point),
point_average_(point_average), normal_(normal), imu_tran_(imu_tran),
imu_tran_orig_(imu_tran_orig) {}
//析构函数
~BalmVoxelEnergy2() {}
//ceres代价函数需要用模板构造仿函数实现
template <typename T>
bool operator()(const T *const q, const T *const t, T *residual) const {
T cur_p[3];
cur_p[0] = T(current_laser_point_(0));
cur_p[1] = T(current_laser_point_(1));
cur_p[2] = T(current_laser_point_(2));
T world_p[3];
//给出旋转向量q,由cur_p得到world_p
ceres::QuaternionRotatePoint(q, cur_p, world_p);
// ceres::AngleAxisRotatePoint(q, cur_p, world_p);
world_p[0] += t[0];
world_p[1] += t[1];
// world_p[2] += t[2];
T tran_p[3];
// transform point average and surface normal变换点平均和曲面法线
T tran_point_aver[3];//变换点平均值
T tran_normal[3];//变换正常值
T orig_point_aver[3];//原始点平均值
T orig_normal[3];原始正常值
orig_point_aver[0] = T(point_average_(0));
orig_point_aver[1] = T(point_average_(1));
orig_point_aver[2] = T(point_average_(2));
orig_normal[0] = T(normal_(0));
orig_normal[1] = T(normal_(1));
orig_normal[2] = T(normal_(2));
//给出旋转向量q,由orig_point_aver得到tran_point_aver
ceres::QuaternionRotatePoint(q, orig_point_aver, tran_point_aver);
tran_point_aver[0] += t[0];
tran_point_aver[1] += t[1];
// tran_point_aver[2] += t[2];
//给出旋转向量q,由orig_normal得到tran_normal
ceres::QuaternionRotatePoint(q, orig_normal, tran_normal);
// imu pose
T imu_point_aver[3];//imu点平均值
T imu_normal[3];//imu正常值
imu_point_aver[0] = imu_tran_orig_(0, 0) * tran_point_aver[0] +
imu_tran_orig_(0, 1) * tran_point_aver[1] +
imu_tran_orig_(0, 2) * tran_point_aver[2] +
imu_tran_orig_(0, 3);
imu_point_aver[1] = imu_tran_orig_(1, 0) * tran_point_aver[0] +
imu_tran_orig_(1, 1) * tran_point_aver[1] +
imu_tran_orig_(1, 2) * tran_point_aver[2] +
imu_tran_orig_(1, 3);
imu_point_aver[2] = imu_tran_orig_(2, 0) * tran_point_aver[0] +
imu_tran_orig_(2, 1) * tran_point_aver[1] +
imu_tran_orig_(2, 2) * tran_point_aver[2] +
imu_tran_orig_(2, 3);
imu_normal[0] = imu_tran_orig_(0, 0) * tran_normal[0] +
imu_tran_orig_(0, 1) * tran_normal[1] +
imu_tran_orig_(0, 2) * tran_normal[2];
imu_normal[1] = imu_tran_orig_(1, 0) * tran_normal[0] +
imu_tran_orig_(1, 1) * tran_normal[1] +
imu_tran_orig_(1, 2) * tran_normal[2];
imu_normal[2] = imu_tran_orig_(2, 0) * tran_normal[0] +
imu_tran_orig_(2, 1) * tran_normal[1] +
imu_tran_orig_(2, 2) * tran_normal[2];
// n * (p - p_aver)定义一个残差
tran_p[0] = imu_tran_(0, 0) * world_p[0] + imu_tran_(0, 1) * world_p[1] +
imu_tran_(0, 2) * world_p[2] + imu_tran_(0, 3) -
imu_point_aver[0];
tran_p[1] = imu_tran_(1, 0) * world_p[0] + imu_tran_(1, 1) * world_p[1] +
imu_tran_(1, 2) * world_p[2] + imu_tran_(1, 3) -
imu_point_aver[1];
tran_p[2] = imu_tran_(2, 0) * world_p[0] + imu_tran_(2, 1) * world_p[1] +
imu_tran_(2, 2) * world_p[2] + imu_tran_(2, 3) -
imu_point_aver[2];
residual[0] = imu_normal[0] * tran_p[0] + imu_normal[1] * tran_p[1] +
imu_normal[2] * tran_p[2];
return true;
}
static ceres::CostFunction *Create(const Eigen::Vector3d ¤t_laser_point,
const Eigen::Vector3d &point_average,
const Eigen::Vector3d &normal,
const Eigen::Matrix4d &imu_tran,
const Eigen::Matrix4d &imu_tran_orig) {
//使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二4个是输入维度,即待寻优参数x的维度
auto cost_function =
new ceres::AutoDiffCostFunction<BalmVoxelEnergy2, 1, 4, 3>(
new BalmVoxelEnergy2(current_laser_point, point_average, normal,
imu_tran, imu_tran_orig));
return cost_function;
}
const Eigen::Vector3d current_laser_point_;
const Eigen::Vector3d point_average_;
const Eigen::Vector3d normal_;
const Eigen::Matrix4d imu_tran_;
const Eigen::Matrix4d imu_tran_orig_;
};
定义BalmVoxelEnergy2_NOT类,实现的功能:构造一个代价函数,定义残差,利用ceres的自动求导
struct BalmVoxelEnergy2_NOT {
//构造函数,传入参数,并完成传递
BalmVoxelEnergy2_NOT(const Eigen::Vector3d ¤t_laser_point,
const Eigen::Vector3d &point_average,
const Eigen::Vector3d &normal,
const Eigen::Matrix4d &imu_tran,
const Eigen::Matrix4d &imu_tran_orig)
: current_laser_point_(current_laser_point),
point_average_(point_average), normal_(normal), imu_tran_(imu_tran),
imu_tran_orig_(imu_tran_orig) {}
//析构函数
~BalmVoxelEnergy2_NOT() {}
//ceres代价函数需要用模板构造仿函数实现
template <typename T> bool operator()(const T *const q, T *residual) const {
T cur_p[3];
cur_p[0] = T(current_laser_point_(0));
cur_p[1] = T(current_laser_point_(1));
cur_p[2] = T(current_laser_point_(2));
T world_p[3];
ceres::QuaternionRotatePoint(q, cur_p, world_p);
// ceres::AngleAxisRotatePoint(q, cur_p, world_p);
T tran_p[3];
// transform point average and surface normal变换点平均和曲面法线
T tran_point_aver[3];//变换点平均值
T tran_normal[3];//变换正常
T orig_point_aver[3];//原始点平均值
T orig_normal[3];//原始正常
orig_point_aver[0] = T(point_average_(0));
orig_point_aver[1] = T(point_average_(1));
orig_point_aver[2] = T(point_average_(2));
orig_normal[0] = T(normal_(0));
orig_normal[1] = T(normal_(1));
orig_normal[2] = T(normal_(2));
//给出旋转向量q,由orig_point_aver得到tran_point_aver
ceres::QuaternionRotatePoint(q, orig_point_aver, tran_point_aver);
//给出旋转向量q,由orig_normal得到tran_normal
ceres::QuaternionRotatePoint(q, orig_normal, tran_normal);
// imu pose
T imu_point_aver[3];//imu点平均值
T imu_normal[3];//imu正常值
imu_point_aver[0] = imu_tran_orig_(0, 0) * tran_point_aver[0] +
imu_tran_orig_(0, 1) * tran_point_aver[1] +
imu_tran_orig_(0, 2) * tran_point_aver[2] +
imu_tran_orig_(0, 3);
imu_point_aver[1] = imu_tran_orig_(1, 0) * tran_point_aver[0] +
imu_tran_orig_(1, 1) * tran_point_aver[1] +
imu_tran_orig_(1, 2) * tran_point_aver[2] +
imu_tran_orig_(1, 3);
imu_point_aver[2] = imu_tran_orig_(2, 0) * tran_point_aver[0] +
imu_tran_orig_(2, 1) * tran_point_aver[1] +
imu_tran_orig_(2, 2) * tran_point_aver[2] +
imu_tran_orig_(2, 3);
imu_normal[0] = imu_tran_orig_(0, 0) * tran_normal[0] +
imu_tran_orig_(0, 1) * tran_normal[1] +
imu_tran_orig_(0, 2) * tran_normal[2];
imu_normal[1] = imu_tran_orig_(1, 0) * tran_normal[0] +
imu_tran_orig_(1, 1) * tran_normal[1] +
imu_tran_orig_(1, 2) * tran_normal[2];
imu_normal[2] = imu_tran_orig_(2, 0) * tran_normal[0] +
imu_tran_orig_(2, 1) * tran_normal[1] +
imu_tran_orig_(2, 2) * tran_normal[2];
// n * (p - p_aver)定义残差
tran_p[0] = imu_tran_(0, 0) * world_p[0] + imu_tran_(0, 1) * world_p[1] +
imu_tran_(0, 2) * world_p[2] + imu_tran_(0, 3) -
imu_point_aver[0];
tran_p[1] = imu_tran_(1, 0) * world_p[0] + imu_tran_(1, 1) * world_p[1] +
imu_tran_(1, 2) * world_p[2] + imu_tran_(1, 3) -
imu_point_aver[1];
tran_p[2] = imu_tran_(2, 0) * world_p[0] + imu_tran_(2, 1) * world_p[1] +
imu_tran_(2, 2) * world_p[2] + imu_tran_(2, 3) -
imu_point_aver[2];
residual[0] = imu_normal[0] * tran_p[0] + imu_normal[1] * tran_p[1] +
imu_normal[2] * tran_p[2];
return true;
}
static ceres::CostFunction *Create(const Eigen::Vector3d ¤t_laser_point,
const Eigen::Vector3d &point_average,
const Eigen::Vector3d &normal,
const Eigen::Matrix4d &imu_tran,
const Eigen::Matrix4d &imu_tran_orig) {
//使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个是输入维度,即待寻优参数x的维度
auto cost_function =
new ceres::AutoDiffCostFunction<BalmVoxelEnergy2_NOT, 1, 4>(
new BalmVoxelEnergy2_NOT(current_laser_point, point_average, normal,
imu_tran, imu_tran_orig));
return cost_function;
}
const Eigen::Vector3d current_laser_point_;
const Eigen::Vector3d point_average_;
const Eigen::Vector3d normal_;
const Eigen::Matrix4d imu_tran_;
const Eigen::Matrix4d imu_tran_orig_;
};
定义BalmVoxelEnergy3类,实现的功能:构造一个代价函数,定义残差,利用ceres的自动求导
struct BalmVoxelEnergy3 {
//构造函数,传入参数,完成赋值
BalmVoxelEnergy3(
const Eigen::Vector3d &cur_laser_point,
const Eigen::Matrix4d &cur_imu_tran,
const std::vector<std::vector<Eigen::Vector3d> *> &orig_laser_points,
const std::vector<pcl::PointXYZINormal> &ap_centor_origns,
const std::vector<Eigen::Matrix4d> &imu_trans)
: cur_laser_point_(cur_laser_point), cur_imu_tran_(cur_imu_tran),
orig_laser_points_(orig_laser_points),
ap_centor_origns_(ap_centor_origns), imu_trans_(imu_trans) {}
//析构函数
~BalmVoxelEnergy3() {}
//ceres代价函数需要用利用模板构建仿函数实现
template <typename T>
bool operator()(const T *const q, const T *const t, T *residual) const {
T real_window_size = T(0);//实际窗口大小
T overall_point_aver[3] = {T(0), T(0), T(0)};//全部点平均
T overall_normal[3] = {T(0), T(0), T(0)};//全部正常
// transform point average and surface normal变换点平均和曲面法线
//遍历每个原始激光雷达点数据
for (int i = 0; i < orig_laser_points_.size(); i++) {
if (orig_laser_points_[i]->size() <= 0)
continue;
real_window_size += T(1);
// int asize = current_laser_points_[i] -> size();
T tran_point_aver[3];//变换点平均值
T tran_normal[3];//变换正常
T orig_point_aver[3];//原始点平均值
T orig_normal[3];//原始正常
orig_point_aver[0] = T(ap_centor_origns_[i].x);
orig_point_aver[1] = T(ap_centor_origns_[i].y);
orig_point_aver[2] = T(ap_centor_origns_[i].z);
orig_normal[0] = T(ap_centor_origns_[i].normal_x);
orig_normal[1] = T(ap_centor_origns_[i].normal_y);
orig_normal[2] = T(ap_centor_origns_[i].normal_z);
//给出旋转向量q,由orig_point_aver得到tran_point_aver
ceres::QuaternionRotatePoint(q, orig_point_aver, tran_point_aver);
tran_point_aver[0] += t[0];
tran_point_aver[1] += t[1];
// tran_point_aver[2] += t[2];
//给出旋转向量q,由orig_normal得到tran_normal
ceres::QuaternionRotatePoint(q, orig_normal, tran_normal);
Eigen::Matrix4d imu_tran_orign = imu_trans_[i];
// imu pose
T imu_point_aver[3];//imu点平均值
T imu_normal[3];//imu正常
imu_point_aver[0] = imu_tran_orign(0, 0) * tran_point_aver[0] +
imu_tran_orign(0, 1) * tran_point_aver[1] +
imu_tran_orign(0, 2) * tran_point_aver[2] +
imu_tran_orign(0, 3);
imu_point_aver[1] = imu_tran_orign(1, 0) * tran_point_aver[0] +
imu_tran_orign(1, 1) * tran_point_aver[1] +
imu_tran_orign(1, 2) * tran_point_aver[2] +
imu_tran_orign(1, 3);
imu_point_aver[2] = imu_tran_orign(2, 0) * tran_point_aver[0] +
imu_tran_orign(2, 1) * tran_point_aver[1] +
imu_tran_orign(2, 2) * tran_point_aver[2] +
imu_tran_orign(2, 3);
imu_normal[0] = imu_tran_orign(0, 0) * tran_normal[0] +
imu_tran_orign(0, 1) * tran_normal[1] +
imu_tran_orign(0, 2) * tran_normal[2];
imu_normal[1] = imu_tran_orign(1, 0) * tran_normal[0] +
imu_tran_orign(1, 1) * tran_normal[1] +
imu_tran_orign(1, 2) * tran_normal[2];
imu_normal[2] = imu_tran_orign(2, 0) * tran_normal[0] +
imu_tran_orign(2, 1) * tran_normal[1] +
imu_tran_orign(2, 2) * tran_normal[2];
// add to overall point average
overall_point_aver[0] += imu_point_aver[0];
overall_point_aver[1] += imu_point_aver[1];
overall_point_aver[2] += imu_point_aver[2];
overall_normal[0] += imu_normal[0];
overall_normal[1] += imu_normal[1];
overall_normal[2] += imu_normal[2];
}
//得到全部激光雷达点云数据的均值
overall_point_aver[0] /= real_window_size;
overall_point_aver[1] /= real_window_size;
overall_point_aver[2] /= real_window_size;
overall_normal[0] /= real_window_size;
overall_normal[1] /= real_window_size;
overall_normal[2] /= real_window_size;
// add residuals
T cur_p[3];
cur_p[0] = T(cur_laser_point_(0));
cur_p[1] = T(cur_laser_point_(1));
cur_p[2] = T(cur_laser_point_(2));
T world_p[3];
//给出旋转四元数q,由cur_p得到world_p
ceres::QuaternionRotatePoint(q, cur_p, world_p);
// ceres::AngleAxisRotatePoint(q, cur_p, world_p);
world_p[0] += t[0];
world_p[1] += t[1];
// world_p[2] += t[2];
T tran_p[3];
// n * (p - p_aver)定义残差
tran_p[0] = cur_imu_tran_(0, 0) * world_p[0] +
cur_imu_tran_(0, 1) * world_p[1] +
cur_imu_tran_(0, 2) * world_p[2] + cur_imu_tran_(0, 3) -
overall_point_aver[0];
tran_p[1] = cur_imu_tran_(1, 0) * world_p[0] +
cur_imu_tran_(1, 1) * world_p[1] +
cur_imu_tran_(1, 2) * world_p[2] + cur_imu_tran_(1, 3) -
overall_point_aver[1];
tran_p[2] = cur_imu_tran_(2, 0) * world_p[0] +
cur_imu_tran_(2, 1) * world_p[1] +
cur_imu_tran_(2, 2) * world_p[2] + cur_imu_tran_(2, 3) -
overall_point_aver[2];
residual[0] = overall_normal[0] * tran_p[0] +
overall_normal[1] * tran_p[1] + overall_normal[2] * tran_p[2];
return true;
}
static ceres::CostFunction *
Create(const Eigen::Vector3d &cur_laser_point,
const Eigen::Matrix4d &cur_imu_tran,
const std::vector<std::vector<Eigen::Vector3d> *> &orig_laser_points,
const std::vector<pcl::PointXYZINormal> &ap_centor_origns,
const std::vector<Eigen::Matrix4d> &imu_trans) {
//使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个是输入维度,即待寻优参数x的维度
auto cost_function =
new ceres::AutoDiffCostFunction<BalmVoxelEnergy3, 1, 4, 3>(
new BalmVoxelEnergy3(cur_laser_point, cur_imu_tran,
orig_laser_points, ap_centor_origns,
imu_trans));
// cost_function.SetNumResiduals(point_size);
return cost_function;
}
const Eigen::Vector3d cur_laser_point_;
const Eigen::Matrix4d cur_imu_tran_;
const std::vector<std::vector<Eigen::Vector3d> *> orig_laser_points_;
const std::vector<pcl::PointXYZINormal> ap_centor_origns_;
const std::vector<Eigen::Matrix4d> imu_trans_;
};
struct BalmVoxelTransEnergy {
//构造函数,传递参数,完成赋值
BalmVoxelTransEnergy(const Eigen::Vector3d ¤t_laser_point,
const Eigen::Vector3d &point_average,
const Eigen::Vector3d &normal,
const Eigen::Matrix4d &imu_tran,
const Eigen::Matrix4d &imu_tran_orig,
const Eigen::Matrix4d &refined_calib_mat)
: current_laser_point_(current_laser_point),
point_average_(point_average), normal_(normal), imu_tran_(imu_tran),
imu_tran_orig_(imu_tran_orig), refined_calib_mat_(refined_calib_mat) {}
//析构函数
~BalmVoxelTransEnergy() {}
//ceres构造代价函数需要借助模板搭建仿函数实现
template <typename T> bool operator()(const T *const t, T *residual) const {
T cur_p[3];
cur_p[0] = T(current_laser_point_(0));
cur_p[1] = T(current_laser_point_(1));
cur_p[2] = T(current_laser_point_(2));
T world_p[3];
world_p[0] = refined_calib_mat_(0, 0) * cur_p[0] +
refined_calib_mat_(0, 1) * cur_p[1] +
refined_calib_mat_(0, 2) * cur_p[2] + refined_calib_mat_(0, 3);
world_p[1] = refined_calib_mat_(1, 0) * cur_p[0] +
refined_calib_mat_(1, 1) * cur_p[1] +
refined_calib_mat_(1, 2) * cur_p[2] + refined_calib_mat_(1, 3);
world_p[2] = refined_calib_mat_(2, 0) * cur_p[0] +
refined_calib_mat_(2, 1) * cur_p[1] +
refined_calib_mat_(2, 2) * cur_p[2] + t[2];
T tran_p[3];
// transform point average and surface normal变换点平均和曲面法线
T tran_point_aver[3];//变换点平均
T tran_normal[3];//变换正常
T orig_point_aver[3];//原始点平均
T orig_normal[3];//原始正常
orig_point_aver[0] = T(point_average_(0));
orig_point_aver[1] = T(point_average_(1));
orig_point_aver[2] = T(point_average_(2));
orig_normal[0] = T(normal_(0));
orig_normal[1] = T(normal_(1));
orig_normal[2] = T(normal_(2));
tran_point_aver[0] = refined_calib_mat_(0, 0) * orig_point_aver[0] +
refined_calib_mat_(0, 1) * orig_point_aver[1] +
refined_calib_mat_(0, 2) * orig_point_aver[2] +
refined_calib_mat_(0, 3);
tran_point_aver[1] = refined_calib_mat_(1, 0) * orig_point_aver[0] +
refined_calib_mat_(1, 1) * orig_point_aver[1] +
refined_calib_mat_(1, 2) * orig_point_aver[2] +
refined_calib_mat_(1, 3);
tran_point_aver[2] = refined_calib_mat_(2, 0) * orig_point_aver[0] +
refined_calib_mat_(2, 1) * orig_point_aver[1] +
refined_calib_mat_(2, 2) * orig_point_aver[2] + t[2];
tran_normal[0] = refined_calib_mat_(0, 0) * orig_normal[0] +
refined_calib_mat_(0, 1) * orig_normal[1] +
refined_calib_mat_(0, 2) * orig_normal[2];
tran_normal[1] = refined_calib_mat_(1, 0) * orig_normal[0] +
refined_calib_mat_(1, 1) * orig_normal[1] +
refined_calib_mat_(1, 2) * orig_normal[2];
tran_normal[2] = refined_calib_mat_(2, 0) * orig_normal[0] +
refined_calib_mat_(2, 1) * orig_normal[1] +
refined_calib_mat_(2, 2) * orig_normal[2];
// imu pose
T imu_point_aver[3];//imu点平均
T imu_normal[3];//imu正常
imu_point_aver[0] = imu_tran_orig_(0, 0) * tran_point_aver[0] +
imu_tran_orig_(0, 1) * tran_point_aver[1] +
imu_tran_orig_(0, 2) * tran_point_aver[2] +
imu_tran_orig_(0, 3);
imu_point_aver[1] = imu_tran_orig_(1, 0) * tran_point_aver[0] +
imu_tran_orig_(1, 1) * tran_point_aver[1] +
imu_tran_orig_(1, 2) * tran_point_aver[2] +
imu_tran_orig_(1, 3);
imu_point_aver[2] = imu_tran_orig_(2, 0) * tran_point_aver[0] +
imu_tran_orig_(2, 1) * tran_point_aver[1] +
imu_tran_orig_(2, 2) * tran_point_aver[2] +
imu_tran_orig_(2, 3);
imu_normal[0] = imu_tran_orig_(0, 0) * tran_normal[0] +
imu_tran_orig_(0, 1) * tran_normal[1] +
imu_tran_orig_(0, 2) * tran_normal[2];
imu_normal[1] = imu_tran_orig_(1, 0) * tran_normal[0] +
imu_tran_orig_(1, 1) * tran_normal[1] +
imu_tran_orig_(1, 2) * tran_normal[2];
imu_normal[2] = imu_tran_orig_(2, 0) * tran_normal[0] +
imu_tran_orig_(2, 1) * tran_normal[1] +
imu_tran_orig_(2, 2) * tran_normal[2];
// n * (p - p_aver)定义残差
tran_p[0] = imu_tran_(0, 0) * world_p[0] + imu_tran_(0, 1) * world_p[1] +
imu_tran_(0, 2) * world_p[2] + imu_tran_(0, 3) -
imu_point_aver[0];
tran_p[1] = imu_tran_(1, 0) * world_p[0] + imu_tran_(1, 1) * world_p[1] +
imu_tran_(1, 2) * world_p[2] + imu_tran_(1, 3) -
imu_point_aver[1];
tran_p[2] = imu_tran_(2, 0) * world_p[0] + imu_tran_(2, 1) * world_p[1] +
imu_tran_(2, 2) * world_p[2] + imu_tran_(2, 3) -
imu_point_aver[2];
residual[0] = imu_normal[0] * tran_p[0] + imu_normal[1] * tran_p[1] +
imu_normal[2] * tran_p[2];
return true;
}
static ceres::CostFunction *Create(const Eigen::Vector3d ¤t_laser_point,
const Eigen::Vector3d &point_average,
const Eigen::Vector3d &normal,
const Eigen::Matrix4d &imu_tran,
const Eigen::Matrix4d &imu_tran_orig,
const Eigen::Matrix4d &refined_calib_mat) {
//使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个是输入维度,即待寻优参数x的维度
auto cost_function =
new ceres::AutoDiffCostFunction<BalmVoxelTransEnergy, 1, 3>(
new BalmVoxelTransEnergy(current_laser_point, point_average, normal,
imu_tran, imu_tran_orig,
refined_calib_mat));
return cost_function;
}
const Eigen::Vector3d current_laser_point_;
const Eigen::Vector3d point_average_;
const Eigen::Vector3d normal_;
const Eigen::Matrix4d imu_tran_;
const Eigen::Matrix4d imu_tran_orig_;
const Eigen::Matrix4d refined_calib_mat_;
};
参考连接: