|
@@ -2,7 +2,7 @@
|
|
|
* @Description:
|
|
|
* @Author: yct
|
|
|
* @Date: 2021-09-16 15:18:34
|
|
|
- * @LastEditTime: 2021-10-12 17:38:39
|
|
|
+ * @LastEditTime: 2021-11-17 15:37:25
|
|
|
* @LastEditors: yct
|
|
|
*/
|
|
|
|
|
@@ -50,6 +50,309 @@ void Car_pose_detector::create_curve_cloud(pcl::PointCloud<pcl::PointXYZ>::Ptr &
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 代价函数的计算模型
|
|
|
+struct Car_pose_cost
|
|
|
+{
|
|
|
+ Car_pose_cost(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr) : m_cloud_ptr(cloud_ptr) {}
|
|
|
+
|
|
|
+ // 残差的计算
|
|
|
+ template <typename T>
|
|
|
+ bool operator()(
|
|
|
+ const T *const vars, // 模型参数,x y theta w
|
|
|
+ T *residual) const
|
|
|
+ {
|
|
|
+ if (m_cloud_ptr == nullptr || m_cloud_ptr->size() <= 0)
|
|
|
+ {
|
|
|
+ std::cout << "error occured" << std::endl;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const T norm_scale = T(0.002);
|
|
|
+ //residual[0] = T(0);
|
|
|
+ // residual[1] = T(0);
|
|
|
+ // residual[m_cloud_ptr->size()] = T(0.0);
|
|
|
+ // 点云loss
|
|
|
+ const T width = T(2.0); //vars[3];
|
|
|
+
|
|
|
+ char buf[40960]={0};
|
|
|
+ // sprintf(buf, "----");
|
|
|
+ for (int i = 0; i < m_cloud_ptr->size(); i++)
|
|
|
+ {
|
|
|
+ Eigen::Matrix<T, 2, 1> t_point(T(m_cloud_ptr->points[i].x) - vars[0], T(m_cloud_ptr->points[i].y) - vars[1]);
|
|
|
+ Eigen::Rotation2D<T> rotation(vars[2]);
|
|
|
+ Eigen::Matrix<T, 2, 2> rotation_matrix = rotation.toRotationMatrix();
|
|
|
+ Eigen::Matrix<T, 2, 1> t_trans_point = rotation_matrix * t_point;
|
|
|
+
|
|
|
+ T left_loss = T(1.0) / (T(1.0) + ceres::exp(T(30.0) * (t_trans_point.x() + width / T(2.0))));
|
|
|
+ T right_loss = T(1.0) / (T(1.0) + ceres::exp(T(30.0) * (-t_trans_point.x() + width / T(2.0))));
|
|
|
+ T front_loss = T(1.0) / (T(1.0) + ceres::exp(T(15.0) * (t_trans_point.y() + T(2.2))));
|
|
|
+ T back_loss = T(1.0) / (T(1.0) + ceres::exp(T(15.0) * (-t_trans_point.y() + T(2.2))));
|
|
|
+ residual[i] = left_loss + right_loss + front_loss + back_loss; // + norm_scale * ((left_loss - T(0.5)) + (right_loss - T(0.5)));
|
|
|
+ // residual[m_cloud_ptr->size()] += (left_loss - T(0.5)) + (right_loss - T(0.5));
|
|
|
+ // if(left_loss > T(0.01))
|
|
|
+ // std::cout << "index l r: " << i << ", " << left_loss << ", " << right_loss << ", " << trans_point.x() << std::endl;
|
|
|
+ // sprintf(buf + strlen(buf), "%.4f ", residual[i]);
|
|
|
+ // if(i%20==8)
|
|
|
+ // {
|
|
|
+ // sprintf(buf + strlen(buf), "\n");
|
|
|
+ // }
|
|
|
+ }
|
|
|
+ // printf(buf);
|
|
|
+
|
|
|
+ // // 参数L2正则化loss
|
|
|
+ // residual[m_cloud_ptr->size()] = T(m_cloud_ptr->size()) * width * norm_scale;
|
|
|
+ // residual[1] += ceres::pow(vars[1],2) * norm_scale;
|
|
|
+ // residual[1] += ceres::pow(vars[2],2) * norm_scale;
|
|
|
+ // residual[1] += ceres::pow((vars[3]-T(1.8)),2) * norm_scale;
|
|
|
+ // ((i != 3) ? norm_scale : norm_scale * T(m_cloud_ptr->size()));
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr m_cloud_ptr; // x,y数据
|
|
|
+};
|
|
|
+
|
|
|
+// 公式转图片优化
|
|
|
+#include <ceres/cubic_interpolation.h>
|
|
|
+
|
|
|
+constexpr float kMinProbability = 0.01f;
|
|
|
+constexpr float kMaxProbability = 1.f - kMinProbability;
|
|
|
+constexpr float kMaxCorrespondenceCost = 1.f - kMinProbability;
|
|
|
+constexpr int kPadding = INT_MAX / 4;
|
|
|
+constexpr float resolutionx = 0.01f;
|
|
|
+constexpr float resolutiony = 0.01f;
|
|
|
+constexpr float min_x = -2.0f;
|
|
|
+constexpr float min_y = -3.0f;
|
|
|
+constexpr float max_x = 2.0f;
|
|
|
+constexpr float max_y = 3.0f;
|
|
|
+
|
|
|
+cv::Mat Car_pose_detector::m_model = Car_pose_detector::create_mat(min_x, max_x, min_y, max_y, resolutionx, resolutiony);
|
|
|
+
|
|
|
+class GridArrayAdapter
|
|
|
+{
|
|
|
+public:
|
|
|
+ enum { DATA_DIMENSION = 1 };
|
|
|
+
|
|
|
+ explicit GridArrayAdapter(const cv::Mat& grid) : grid_(grid) {}
|
|
|
+
|
|
|
+ void GetValue(const int row, const int column, double* const value) const {
|
|
|
+ if (row < kPadding || column < kPadding || row >= NumRows() - kPadding ||
|
|
|
+ column >= NumCols() - kPadding) {
|
|
|
+ *value = kMaxCorrespondenceCost;
|
|
|
+ } else {
|
|
|
+ *value = static_cast<double>(grid_.at<float>(row - kPadding, column - kPadding));
|
|
|
+ // if (row - kPadding > 100 && row - kPadding < 300 && column - kPadding > 50 && column - kPadding < 150)
|
|
|
+ // printf("row:%d, col:%d, val%.3f\n", row-kPadding, column-kPadding, grid_.at<float>(row - kPadding, column - kPadding));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ int NumRows() const {
|
|
|
+ return grid_.rows + 2 * kPadding;
|
|
|
+ }
|
|
|
+
|
|
|
+ int NumCols() const {
|
|
|
+ return grid_.cols + 2 * kPadding;
|
|
|
+ }
|
|
|
+private:
|
|
|
+ const cv::Mat& grid_;
|
|
|
+};
|
|
|
+
|
|
|
+// 代价函数的计算模型
|
|
|
+struct Trans_mat_cost
|
|
|
+{
|
|
|
+ Trans_mat_cost(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr, cv::Mat &mat) : m_cloud_ptr(cloud_ptr), m_mat(mat) {
|
|
|
+ // cv::namedWindow("img", CV_WINDOW_FREERATIO);
|
|
|
+ // cv::imshow("img", m_mat);
|
|
|
+ // cv::waitKey();
|
|
|
+ // debug_img(cloud_ptr, mat);
|
|
|
+ }
|
|
|
+
|
|
|
+ void debug_img(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr, cv::Mat &mat)
|
|
|
+ {
|
|
|
+ if (m_cloud_ptr == nullptr || m_cloud_ptr->size() <= 0)
|
|
|
+ {
|
|
|
+ std::cout << "error occured" << std::endl;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ cv::Mat img_show = mat.clone();//cv::Mat::zeros(mat.rows * 1, mat.cols * 1, CV_32FC1);
|
|
|
+ const GridArrayAdapter adapter(mat);
|
|
|
+ ceres::BiCubicInterpolator<GridArrayAdapter> interpolator(adapter);
|
|
|
+
|
|
|
+ // 点云loss
|
|
|
+ // char buf[150960]={0};
|
|
|
+ // sprintf(buf, "----");
|
|
|
+ for (int i = 0; i < m_cloud_ptr->size(); i++)
|
|
|
+ {
|
|
|
+ Eigen::Matrix<double, 2, 1> t_point(double(m_cloud_ptr->points[i].x), double(m_cloud_ptr->points[i].y));
|
|
|
+ Eigen::Rotation2D<double> rotation(0);
|
|
|
+ Eigen::Matrix<double, 2, 2> rotation_matrix = rotation.toRotationMatrix();
|
|
|
+ Eigen::Matrix<double, 2, 1> t_trans_point = rotation_matrix * t_point;
|
|
|
+
|
|
|
+ int col_index = int((t_trans_point.x() - min_x) / resolutionx);
|
|
|
+ int row_index = int((t_trans_point.y() - min_y) / resolutiony);
|
|
|
+ double val=0.0;
|
|
|
+ interpolator.Evaluate(row_index +0.5+ kPadding, col_index +0.5+ kPadding, &val);
|
|
|
+ cv::circle(img_show, cv::Point(col_index, row_index), 1, cv::Scalar(0.25), 1);
|
|
|
+ // sprintf(buf + strlen(buf), "(%.2f,%.2f)---%.3f ", t_trans_point.x(), t_trans_point.y(), val);
|
|
|
+ // if(i%15==8)
|
|
|
+ // {
|
|
|
+ // sprintf(buf + strlen(buf), "\n");
|
|
|
+ // }
|
|
|
+ }
|
|
|
+ // printf(buf);
|
|
|
+ // for (size_t i = -mat.rows; i < mat.rows*2; i++)
|
|
|
+ // {
|
|
|
+ // for (size_t j = -mat.cols; j < mat.cols*2; j++)
|
|
|
+ // {
|
|
|
+ // double val;
|
|
|
+ // // adapter.GetValue(i + kPadding, j + kPadding, &val);
|
|
|
+ // interpolator.Evaluate(i+kPadding, j+kPadding, &val);
|
|
|
+ // img_show.at<float>(i, j) = val;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // printf("r:%d c:%d\n", img_show.rows, img_show.cols);
|
|
|
+ cv::namedWindow("img", CV_WINDOW_FREERATIO);
|
|
|
+ // cv::imshow("origin", mat);
|
|
|
+ cv::imshow("img", img_show);
|
|
|
+ cv::waitKey();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 残差的计算
|
|
|
+ template <typename T>
|
|
|
+ bool operator()(
|
|
|
+ const T *const vars, // 模型参数,x y theta w
|
|
|
+ T *residual) const
|
|
|
+ {
|
|
|
+ if (m_cloud_ptr == nullptr || m_cloud_ptr->size() <= 0)
|
|
|
+ {
|
|
|
+ std::cout << "error occured" << std::endl;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const GridArrayAdapter adapter(m_mat);
|
|
|
+ ceres::BiCubicInterpolator<GridArrayAdapter> interpolator(adapter);
|
|
|
+
|
|
|
+ // 点云loss
|
|
|
+ Eigen::Rotation2D<T> rotation(vars[2]);
|
|
|
+ Eigen::Matrix<T, 2, 2> rotation_matrix = rotation.toRotationMatrix();
|
|
|
+ for (int i = 0; i < m_cloud_ptr->size(); i++)
|
|
|
+ {
|
|
|
+ Eigen::Matrix<T, 2, 1> t_point(T(m_cloud_ptr->points[i].x) - vars[0], T(m_cloud_ptr->points[i].y) - vars[1]);
|
|
|
+ Eigen::Matrix<T, 2, 1> t_trans_point = rotation_matrix * t_point;
|
|
|
+
|
|
|
+ T col_index = (t_trans_point.x() - T(min_x)) / T(resolutionx) + T(0.5+kPadding);
|
|
|
+ T row_index = (t_trans_point.y() - T(min_y)) / T(resolutiony) + T(0.5+kPadding);
|
|
|
+ interpolator.Evaluate(row_index, col_index, &residual[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // // 参数L2正则化loss
|
|
|
+ // residual[m_cloud_ptr->size()] = T(m_cloud_ptr->size()) * width * norm_scale;
|
|
|
+ // residual[1] += ceres::pow(vars[1],2) * norm_scale;
|
|
|
+ // residual[1] += ceres::pow(vars[2],2) * norm_scale;
|
|
|
+ // residual[1] += ceres::pow((vars[3]-T(1.8)),2) * norm_scale;
|
|
|
+ // ((i != 3) ? norm_scale : norm_scale * T(m_cloud_ptr->size()));
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr m_cloud_ptr; // x,y数据
|
|
|
+ cv::Mat m_mat;
|
|
|
+};
|
|
|
+
|
|
|
+// 生成优化图像,降低优化耗时
|
|
|
+cv::Mat Car_pose_detector::create_mat(double min_x, double max_x, double min_y, double max_y, double resolution_x, double resolution_y)
|
|
|
+{
|
|
|
+ if (max_x < min_x || max_y < min_y || resolution_x <= 0 || resolution_y <= 0)
|
|
|
+ {
|
|
|
+ return cv::Mat();
|
|
|
+ }
|
|
|
+ int cols = (max_x - min_x) / resolution_x + 1;
|
|
|
+ int rows = (max_y - min_y) / resolution_y + 1;
|
|
|
+ if(rows <=1 || cols <=1)
|
|
|
+ {
|
|
|
+ return cv::Mat();
|
|
|
+ }
|
|
|
+ cv::Mat t_mat(rows, cols, CV_32FC1);
|
|
|
+
|
|
|
+ for (size_t i = 0; i < rows; i++)
|
|
|
+ {
|
|
|
+ for (size_t j = 0; j < cols; j++)
|
|
|
+ {
|
|
|
+ double x = j * resolution_x + min_x;
|
|
|
+ double y = i * resolution_y + min_y;
|
|
|
+ double left_value = 1.0 / (1.0 + exp(30 * (x + 1.0)));
|
|
|
+ double right_value = 1.0 / (1.0 + exp(30 * (-x + 1.0)));
|
|
|
+ double front_value = 1.0 / (1.0 + exp(15 * (y + 2.2)));
|
|
|
+ double back_value = 1.0 / (1.0 + exp(15 * (-y + 2.2)));
|
|
|
+ t_mat.at<float>(i, j) = float((left_value + right_value + front_value + back_value) / 1.0f);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // std::cout << "r,c " << t_mat.rows << ", " << t_mat.cols << std::endl;
|
|
|
+ // cv::imshow("img", t_mat);
|
|
|
+ // cv::waitKey();
|
|
|
+
|
|
|
+ return t_mat;
|
|
|
+}
|
|
|
+
|
|
|
+// 检测底盘z方向值,去中心,使用mat加速
|
|
|
+bool Car_pose_detector::detect_pose_mat(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr, pcl::PointCloud<pcl::PointXYZ>::Ptr out_cloud_ptr, double &x, double &y, double &theta, bool debug_cloud)
|
|
|
+{
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr t_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
|
|
|
+ t_cloud->operator+=(*cloud_ptr);
|
|
|
+ double t_vars[4] = {0, 0, 0, 1.9};
|
|
|
+ // 去中心化
|
|
|
+ pcl::PointXYZ t_center(0, 0, 0);
|
|
|
+ for (size_t i = 0; i < t_cloud->size(); i++)
|
|
|
+ {
|
|
|
+ t_center.x += t_cloud->points[i].x;
|
|
|
+ t_center.y += t_cloud->points[i].y;
|
|
|
+ }
|
|
|
+ t_center.x /= t_cloud->size();
|
|
|
+ t_center.y /= t_cloud->size();
|
|
|
+ for (size_t i = 0; i < t_cloud->size(); i++)
|
|
|
+ {
|
|
|
+ t_cloud->points[i].x -= t_center.x;
|
|
|
+ t_cloud->points[i].y -= t_center.y;
|
|
|
+ }
|
|
|
+ // // write_pointcloud(t_cloud, std::to_string(count)+"_ori_");
|
|
|
+
|
|
|
+ // 构建最小二乘问题
|
|
|
+ ceres::Problem problem;
|
|
|
+ Trans_mat_cost *tp_trans_mat_cost = new Trans_mat_cost(t_cloud, m_model);
|
|
|
+ // tp_trans_mat_cost->debug_img(t_cloud, m_model);
|
|
|
+ problem.AddResidualBlock( // 向问题中添加误差项
|
|
|
+ // 使用自动求导,模板参数:误差类型,输出维度,输入维度,维数要与前面struct中一致
|
|
|
+ new ceres::AutoDiffCostFunction<Trans_mat_cost, ceres::DYNAMIC, 3>(
|
|
|
+ tp_trans_mat_cost, t_cloud->size()),
|
|
|
+ new ceres::HuberLoss(1.0), // 核函数,这里不使用,为空
|
|
|
+ t_vars // 待估计参数
|
|
|
+ );
|
|
|
+
|
|
|
+ // 配置求解器
|
|
|
+ ceres::Solver::Options options; // 这里有很多配置项可以填
|
|
|
+ options.linear_solver_type = ceres::DENSE_QR; // 增量方程如何求解
|
|
|
+ options.minimizer_progress_to_stdout = false; // 输出到cout
|
|
|
+ options.max_num_iterations = 100;
|
|
|
+
|
|
|
+ ceres::Solver::Summary summary; // 优化信息
|
|
|
+ std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
|
|
|
+ ceres::Solve(options, &problem, &summary); // 开始优化
|
|
|
+ std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
|
|
|
+ std::chrono::duration<double> time_used = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);
|
|
|
+ // std::cout << "solve time cost = " << time_used.count() << " seconds. " << std::endl;
|
|
|
+
|
|
|
+ // 输出结果
|
|
|
+ // std::cout << summary.BriefReport() << std::endl;
|
|
|
+ // t_vars[3] -= 0.4;
|
|
|
+ // 保存结果,将去除的中心补上
|
|
|
+ x = t_vars[0] + t_center.x;
|
|
|
+ y = t_vars[1] + t_center.y;
|
|
|
+ theta = t_vars[2];
|
|
|
+ // printf("x:%.3f y:%.3f th:%.3f\n", x, y, theta);
|
|
|
+ if (fabs(theta) > 10 * M_PI / 180.0)
|
|
|
+ {
|
|
|
+ //std::cout << "wrong angle, detect failed" << theta*180.0/M_PI << std::endl;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
// 检测底盘z方向值,原始点云去中心,并切除底盘z以上部分
|
|
|
bool Car_pose_detector::detect_pose(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr, pcl::PointCloud<pcl::PointXYZ>::Ptr out_cloud_ptr, double &x, double &y, double &theta, double &width, double &z_value, bool debug_cloud)
|
|
|
{
|
|
@@ -84,7 +387,7 @@ bool Car_pose_detector::detect_pose(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_pt
|
|
|
// 使用自动求导,模板参数:误差类型,输出维度,输入维度,维数要与前面struct中一致
|
|
|
new ceres::AutoDiffCostFunction<Car_pose_cost, ceres::DYNAMIC, 3>(
|
|
|
new Car_pose_cost(t_cloud), t_cloud->size()),
|
|
|
- nullptr, // 核函数,这里不使用,为空
|
|
|
+ new ceres::HuberLoss(1.0), // 核函数,这里不使用,为空
|
|
|
t_vars // 待估计参数
|
|
|
);
|
|
|
|
|
@@ -99,15 +402,17 @@ bool Car_pose_detector::detect_pose(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_pt
|
|
|
ceres::Solve(options, &problem, &summary); // 开始优化
|
|
|
std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
|
|
|
std::chrono::duration<double> time_used = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);
|
|
|
- // std::cout << "solve time cost = " << time_used.count() << " seconds. " << std::endl;
|
|
|
+ std::cout << "solve time cost = " << time_used.count() << " seconds. " << std::endl;
|
|
|
|
|
|
// 输出结果
|
|
|
// std::cout << summary.BriefReport() << std::endl;
|
|
|
// t_vars[3] -= 0.4;
|
|
|
- x = t_vars[0];
|
|
|
- y = t_vars[1];
|
|
|
+ // 保存结果,将去除的中心补上
|
|
|
+ x = t_vars[0] + t_center.x;
|
|
|
+ y = t_vars[1] + t_center.y;
|
|
|
theta = t_vars[2];
|
|
|
- if(fabs(theta)>30*M_PI/180.0)
|
|
|
+ // printf("x:%.3f y:%.3f th:%.3f\n", x, y, theta);
|
|
|
+ if (fabs(theta) > 10 * M_PI / 180.0)
|
|
|
{
|
|
|
//std::cout << "wrong angle, detect failed" << theta*180.0/M_PI << std::endl;
|
|
|
return false;
|
|
@@ -181,8 +486,6 @@ bool Car_pose_detector::detect_pose(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_pt
|
|
|
out_cloud_ptr->operator+=(*t_cloud);
|
|
|
}
|
|
|
}
|
|
|
- x += t_center.x;
|
|
|
- y += t_center.y;
|
|
|
// std::cout << "estimated x,y,theta = " << x << ", " << y << ", " << theta*180.0/M_PI << std::endl;
|
|
|
// std::cout << "----------------------------------" << std::endl;
|
|
|
return true;
|