//计算激光点到平面的残差,以三个点为平面
struct LidarPlaneFactor {
LidarPlaneFactor(Eigen::Vector3d curr_point_, Eigen::Vector3d last_point_j_,
Eigen::Vector3d last_point_l_, Eigen::Vector3d last_point_m_, double s_)
: curr_point(curr_point_), last_point_j(last_point_j_), last_point_l(last_point_l_),
last_point_m(last_point_m_), s(s_) {// curr_point代表当前点,last_point_j代表前一帧的平面上的第一个点,last_point_l代表前一帧的平面上的第二个点,last_point_m代表前一帧的平面上的第三个点,s代表当前点在前一帧平面上的投影的位置
ljm_norm = (last_point_j - last_point_l).cross(last_point_j - last_point_m);// 前一帧平面上的向量
ljm_norm.normalize();// 前一帧平面上的向量的模
}
template <typename T>
bool operator()(const T* q, const T* t, T* residual) const {
Eigen::Matrix<T, 3, 1> cp{T(curr_point.x()), T(curr_point.y()), T(curr_point.z())};// 当前点
Eigen::Matrix<T, 3, 1> lpj{T(last_point_j.x()), T(last_point_j.y()), T(last_point_j.z())};// 前一帧平面上的第一个点
// Eigen::Matrix<T, 3, 1> lpl{T(last_point_l.x()), T(last_point_l.y()),
// T(last_point_l.z())};
// Eigen::Matrix<T, 3, 1> lpm{T(last_point_m.x()), T(last_point_m.y()),
// T(last_point_m.z())};
Eigen::Matrix<T, 3, 1> ljm{T(ljm_norm.x()), T(ljm_norm.y()), T(ljm_norm.z())};// 前一帧平面上的向量
// Eigen::Quaternion<T> q_last_curr{q[3], T(s) * q[0], T(s) * q[1], T(s) * q[2]};
Eigen::Quaternion<T> q_last_curr{q[3], q[0], q[1], q[2]};// 前一帧到当前帧的旋转
Eigen::Quaternion<T> q_identity{T(1), T(0), T(0), T(0)};// 单位四元数
q_last_curr = q_identity.slerp(T(s), q_last_curr);// 前一帧到当前帧的旋转
Eigen::Matrix<T, 3, 1> t_last_curr{T(s) * t[0], T(s) * t[1], T(s) * t[2]};// 前一帧到当前帧的平移
Eigen::Matrix<T, 3, 1> lp;// 前一帧边上的投影点
lp = q_last_curr * cp + t_last_curr;// 当前点在前一帧的位置
residual[0] = (lp - lpj).dot(ljm);// 误差为当前点到前一帧平面上的投影点的向量与前一帧平面上的向量的点乘
return true;
}
static ceres::CostFunction* Create(const Eigen::Vector3d curr_point_,
const Eigen::Vector3d last_point_j_,
const Eigen::Vector3d last_point_l_,
const Eigen::Vector3d last_point_m_, const double s_) {
return (new ceres::AutoDiffCostFunction<LidarPlaneFactor, 1, 4, 3>(
new LidarPlaneFactor(curr_point_, last_point_j_, last_point_l_, last_point_m_, s_)));
}
Eigen::Vector3d curr_point, last_point_j, last_point_l, last_point_m;
Eigen::Vector3d ljm_norm;
double s;
};
// 计算激光点到平面的残差,以平面的法向量为参数
struct LidarPlaneNormFactor {
LidarPlaneNormFactor(Eigen::Vector3d curr_point_, Eigen::Vector3d plane_unit_norm_,
double negative_OA_dot_norm_)
: curr_point(curr_point_), plane_unit_norm(plane_unit_norm_),
negative_OA_dot_norm(negative_OA_dot_norm_) {}// curr_point代表当前点,plane_unit_norm代表前一帧平面的法向量,negative_OA_dot_norm代表前一帧平面的法向量与前一帧平面上的一个点的点乘
template <typename T>
bool operator()(const T* q, const T* t, T* residual) const {
Eigen::Quaternion<T> q_w_curr{q[3], q[0], q[1], q[2]};// 当前帧到世界坐标系的旋转
Eigen::Matrix<T, 3, 1> t_w_curr{t[0], t[1], t[2]};// 当前帧到世界坐标系的平移
Eigen::Matrix<T, 3, 1> cp{T(curr_point.x()), T(curr_point.y()), T(curr_point.z())};// 当前点
Eigen::Matrix<T, 3, 1> point_w;
point_w = q_w_curr * cp + t_w_curr;// 当前点在世界坐标系下的位置
Eigen::Matrix<T, 3, 1> norm(T(plane_unit_norm.x()), T(plane_unit_norm.y()),
T(plane_unit_norm.z()));// 前一帧平面的法向量
residual[0] = norm.dot(point_w) + T(negative_OA_dot_norm);// 误差为前一帧平面的法向量与当前点在世界坐标系下的位置的点乘
return true;
}
static ceres::CostFunction* Create(const Eigen::Vector3d curr_point_,
const Eigen::Vector3d plane_unit_norm_,
const double negative_OA_dot_norm_) {
return (new ceres::AutoDiffCostFunction<LidarPlaneNormFactor, 1, 4, 3>(
new LidarPlaneNormFactor(curr_point_, plane_unit_norm_, negative_OA_dot_norm_)));// 创建残差块
}
Eigen::Vector3d curr_point;
Eigen::Vector3d plane_unit_norm;
double negative_OA_dot_norm;
};
// ceres::CostFunction* cost_function =
// LidarPlaneNormFactor::Create(curr_point, norm, negative_OA_dot_norm);//点到平面的距离: 点与平面单位法向量的点乘
// problem.AddResidualBlock(cost_function, loss_function, parameters, parameters + 4);