123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- //
- // Created by zx on 2021/9/17.
- //
- #include "chassis_ceres_solver.h"
- const float CERES_PA=(100.);
- const float CERES_PB=(300.);
- const float CERES_PC=(300.);
- class chassis_ceres_cost
- {
- private:
- pcl::PointCloud<pcl::PointXYZ>::Ptr m_cloud; //点云
- public:
- chassis_ceres_cost(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
- :m_cloud(cloud)
- {
- }
- template<typename T>
- bool operator()(const T *const variable, T *residual) const
- {
- T cx = variable[0];
- T cy = variable[1];
- T w=variable[2];
- T h=variable[3];
- const T PA=T(CERES_PA);
- const T PB=T(CERES_PB);
- const T PC=T(CERES_PC);
- //
- for (int i = 0; i < m_cloud->size(); ++i)
- {
- //先平移后旋转
- const Eigen::Matrix<T, 2, 1> point((T(m_cloud->points[i].x)),
- (T(m_cloud->points[i].z)));
- T kx=point(0,0);
- T ky=point(1,0);
- T fx=1.0/(1.0+ceres::exp(-PA*(kx-cx+w/2.0)))-1.0/(1.0+ceres::exp(-PA*(kx-cx-w/2.0)));
- T fy=1.0/(1.0+ceres::exp(-PB*(ky-cy+h/2.0)))-1.0/(1.0+ceres::exp(-PC*((ky-cy)-h/2.0)));
- residual[i] = fx * fy; //+(50./m_cloud->size())/(w*h+1e-16);
- }
- residual[m_cloud->size()] = T(1.0) / (w * h + 1e-16);
- return true;
- }
- };
- // 公式转图片优化
- #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.01;
- constexpr float resolutiony = 0.005;
- constexpr float inner_width = 1.2;
- constexpr float chassis_height = 0.14;
- constexpr float startx = -2.0;
- constexpr float starty = -0.1;
- constexpr float endx = 2.0;
- constexpr float endy = 0.3;
- 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));
- }
- }
- int NumRows() const {
- return grid_.rows + 2 * kPadding;
- }
- int NumCols() const {
- return grid_.cols + 2 * kPadding;
- }
- private:
- const cv::Mat& grid_;
- };
- class chassis_mat_cost
- {
- private:
- pcl::PointCloud<pcl::PointXYZ>::Ptr m_cloud; //点云
- cv::Mat m_mat;
- public:
- chassis_mat_cost(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, cv::Mat mat)
- :m_cloud(cloud),m_mat(mat)
- {
- }
- template<typename T>
- bool operator()(const T *const variable, T *residual) const
- {
- T cx = variable[0];
- T cy = variable[1];
- // T w_ratio = variable[2]/T(inner_width);
- // T h_ratio = variable[3]/T(chassis_height);
- const GridArrayAdapter adapter(m_mat);
- ceres::BiCubicInterpolator<GridArrayAdapter> interpolator(adapter);
- //
- for (int i = 0; i < m_cloud->size(); ++i)
- {
- //先平移后旋转
- const Eigen::Matrix<T, 2, 1> point((T(m_cloud->points[i].x)-cx),
- (T(m_cloud->points[i].z)-cy));
- T kx=(point(0,0)-T(startx)) / T(resolutionx) + T(0.5+kPadding);
- T ky=(point(1,0)-T(starty)) / T(resolutiony) + T(0.5+kPadding);
- interpolator.Evaluate(kx, ky, &residual[i]);
- // residual[i] = fx * fy; //+(50./m_cloud->size())/(w*h+1e-16);
- }
- // residual[m_cloud->size()] = (w_ratio - T(1.0));
- // residual[m_cloud->size()+1] = (h_ratio - T(1.0));
- return true;
- }
- // 生成debug图片
- void generate_mat(cv::Mat &mat, pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, double *variables)
- {
- mat = m_mat.clone();
- // double w_ratio = variables[2] / inner_width;
- // double h_ratio = variables[3] / chassis_height;
- for (size_t i = 0; i < cloud->size(); i++)
- {
- const Eigen::Vector2d point(
- ((cloud->points[i].x - variables[0]) - startx) / resolutionx,
- ((cloud->points[i].z - variables[1]) - starty) / resolutiony);
- cv::circle(mat, cv::Point2d(point.y(), point.x()), 2, cv::Scalar(0.4), 1);
- // std::cout << point.y() << ", " << point.x() << std::endl;
- }
- }
- };
- cv::Mat chassis_ceres_solver::m_model = chassis_ceres_solver::create_mat();
- chassis_ceres_solver::chassis_ceres_solver(){}
- chassis_ceres_solver::~chassis_ceres_solver(){}
- /**
- * @description: 使用sigmoid函数寻找xoz平面平移以及内宽、底盘高度
- */
- Error_manager chassis_ceres_solver::solve(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,double& x,double& y,double& w,double& h)
- {
- double variable[] = {x, y, w, h};
- /*printf("init solve x:%.3f y: %.3f wheel:%.3f width:%.3f theta : %.3f front theta: %.3f\n",
- variable[0], variable[1], variable[3], variable[4], variable[2], variable[5]);*/
- // 第二部分:构建寻优问题
- ceres::Problem problem;
- chassis_ceres_cost *cost_func = new chassis_ceres_cost(cloud);
- //使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个1是输入维度,即待寻优参数x的维度。
- ceres::CostFunction* cost_function =new
- ceres::AutoDiffCostFunction<chassis_ceres_cost, ceres::DYNAMIC, 4>(
- cost_func,cloud->size()+1);
- problem.AddResidualBlock(cost_function, new ceres::HuberLoss(1.0), variable); //向问题中添加误差项,本问题比较简单,添加一个就行。
- //第三部分: 配置并运行求解器
- ceres::Solver::Options options;
- options.use_nonmonotonic_steps=false;
- options.linear_solver_type = ceres::DENSE_QR; //配置增量方程的解法
- //options.logging_type = ceres::LoggingType::SILENT;
- options.max_num_iterations=500;
- options.num_threads=1;
- options.minimizer_progress_to_stdout = false;//输出到cout
- ceres::Solver::Summary summary;//优化信息
- ceres::Solve(options, &problem, &summary);//求解!!!
- double loss=summary.final_cost/(cloud->size());
- x=variable[0];
- y=variable[1];
- w = variable[2];
- h = variable[3];
- // printf(" loss : %f x:%.5f y:%.5f w:%.5f h:%.5f\n",
- // loss,variable[0],variable[1],variable[2],variable[3]);
- return SUCCESS;
- }
- /**
- * @description: 图片代替函数十倍提升优化速度
- */
- Error_manager chassis_ceres_solver::solve_mat(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,double& x,double& y,double& w,double& h, bool update_debug_img)
- {
- // std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
- // create_mat(m_model);
- // cv::imshow("model", m_model);
- // cv::waitKey(30);
- std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
- // std::chrono::duration<double> time_used_mat = std::chrono::duration_cast<std::chrono::duration<double>>(t1 - t0);
- double variable[] = {x, y, w, h};
- /*printf("init solve x:%.3f y: %.3f wheel:%.3f width:%.3f theta : %.3f front theta: %.3f\n",
- variable[0], variable[1], variable[3], variable[4], variable[2], variable[5]);*/
- // 第二部分:构建寻优问题
- ceres::Problem problem;
- chassis_mat_cost *cost_func = new chassis_mat_cost(cloud, m_model);
- //使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个1是输入维度,即待寻优参数x的维度。
- ceres::CostFunction* cost_function =new
- ceres::AutoDiffCostFunction<chassis_mat_cost, ceres::DYNAMIC, 2>(
- cost_func, cloud->size());
- problem.AddResidualBlock(cost_function, new ceres::HuberLoss(1.0), variable); //向问题中添加误差项,本问题比较简单,添加一个就行。
- //第三部分: 配置并运行求解器
- ceres::Solver::Options options;
- options.use_nonmonotonic_steps=false;
- options.linear_solver_type = ceres::DENSE_QR; //配置增量方程的解法
- //options.logging_type = ceres::LoggingType::SILENT;
- options.max_num_iterations=500;
- options.num_threads=1;
- options.minimizer_progress_to_stdout = false;//输出到cout
- ceres::Solver::Summary summary;//优化信息
- ceres::Solve(options, &problem, &summary);//求解!!!
- // std::cout << summary.BriefReport() << std::endl;
- double loss=summary.final_cost/(cloud->size());
- x = variable[0];
- y = variable[1];
- // w = variable[2];
- // h = variable[3];
- // printf(" loss : %f x:%.5f y:%.5f w:%.5f h:%.5f\n",
- // loss,variable[0],variable[1],variable[2],variable[3]);
- std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
- std::chrono::duration<double> time_used_solve = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);
- if(update_debug_img)
- {
- // printf("midx:%.3f, midz:%.3f\n", x, y);
- cost_func->generate_mat(m_projected_mat, cloud, variable);
- cv::namedWindow("win", cv::WINDOW_FREERATIO);
- cv::imshow("win", m_projected_mat);
- cv::waitKey();
- }
- std::chrono::steady_clock::time_point t3 = std::chrono::steady_clock::now();
- std::chrono::duration<double> time_used_disp = std::chrono::duration_cast<std::chrono::duration<double>>(t3 - t2);
- // std::cout << "\ntime used for solve, display in ms: " << time_used_solve.count() << ", " << time_used_disp.count() << std::endl
- // << std::endl;
- return SUCCESS;
- }
- cv::Mat chassis_ceres_solver::create_mat()
- {
- int rows = (endx - startx) / resolutionx + 1;
- int cols = (endy - starty) / resolutiony + 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 = i * resolutionx + startx;
- double y = j * resolutiony + starty;
- double fx = 1.0 / (1.0 + std::exp(-CERES_PA * (x + inner_width / 2.0))) - 1.0 / (1.0 + std::exp(-CERES_PA * (x - inner_width / 2.0)));
- double fy = 1.0 / (1.0 + std::exp(-CERES_PB * (y + chassis_height / 2.0))) - 1.0 / (1.0 + std::exp(-CERES_PC * (y - chassis_height / 2.0)));
- t_mat.at<float>(i, j) = fx * fy;
- // std::cout << "x,y: " << x << ", " << y << "-----value: " << 1.0 / (1.0 + std::exp(-CERES_PA * (x + default_width / 2.0)))<<", "<<
- // 1.0 / (1.0 + std::exp(-CERES_PA * (x - default_width / 2.0))) << std::endl;
- // if(fx*fy>0)
- // std::cout << "x,y: " << x << "," << y << ", fx,fy: " << fx << ", " << fy << ", " << fx * fy << std::endl;
- }
- }
- cv::normalize(t_mat, t_mat, 1.0, 0.1, cv::NORM_MINMAX);
- // std::cout << t_mat << std::endl;
- // cv::namedWindow("win", cv::WINDOW_FREERATIO);
- // cv::imshow("win", t_mat);
- // cv::waitKey(0);
- return t_mat;
- }
- // 返回投影地图转换的点云, 便于投影到pcl视野中
- pcl::PointCloud<pcl::PointXYZ>::Ptr chassis_ceres_solver::get_projected_cloud()
- {
- pcl::PointCloud<pcl::PointXYZ>::Ptr t_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
- if (m_projected_mat.empty())
- return t_cloud;
- for (size_t i = 0; i < m_projected_mat.rows; i++)
- {
- for (size_t j = 0; j < m_projected_mat.cols; j++)
- {
- double x0 = (i * resolutionx + startx);
- t_cloud->push_back(pcl::PointXYZ());
- }
- }
- return t_cloud;
- }
|