chassis_ceres_solver.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. //
  2. // Created by zx on 2021/9/17.
  3. //
  4. #include "chassis_ceres_solver.h"
  5. const float CERES_PA = (100.);
  6. const float CERES_PB = (300.);
  7. const float CERES_PC = (300.);
  8. class chassis_ceres_cost {
  9. private:
  10. pcl::PointCloud<pcl::PointXYZ>::Ptr m_cloud; //点云
  11. public:
  12. chassis_ceres_cost(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
  13. : m_cloud(cloud) {
  14. }
  15. template<typename T>
  16. bool operator()(const T *const variable, T *residual) const {
  17. T cx = variable[0];
  18. T cy = variable[1];
  19. T w = variable[2];
  20. T h = variable[3];
  21. const T PA = T(CERES_PA);
  22. const T PB = T(CERES_PB);
  23. const T PC = T(CERES_PC);
  24. //
  25. for (int i = 0; i < m_cloud->size(); ++i) {
  26. //先平移后旋转
  27. const Eigen::Matrix<T, 2, 1> point((T(m_cloud->points[i].x)),
  28. (T(m_cloud->points[i].z)));
  29. T kx = point(0, 0);
  30. T ky = point(1, 0);
  31. T fx = 1.0 / (1.0 + ceres::exp(-PA * (kx - cx + w / 2.0))) -
  32. 1.0 / (1.0 + ceres::exp(-PA * (kx - cx - w / 2.0)));
  33. T fy = 1.0 / (1.0 + ceres::exp(-PB * (ky - cy + h / 2.0))) -
  34. 1.0 / (1.0 + ceres::exp(-PC * ((ky - cy) - h / 2.0)));
  35. residual[i] = fx * fy; //+(50./m_cloud->size())/(w*h+1e-16);
  36. }
  37. residual[m_cloud->size()] = T(1.0) / (w * h + 1e-16);
  38. return true;
  39. }
  40. };
  41. // 公式转图片优化
  42. #include <ceres/cubic_interpolation.h>
  43. constexpr float kMinProbability = 0.01f;
  44. constexpr float kMaxProbability = 1.f - kMinProbability;
  45. constexpr float kMaxCorrespondenceCost = 1.f - kMinProbability;
  46. constexpr int kPadding = INT_MAX / 4;
  47. constexpr float resolutionx = 0.01;
  48. constexpr float resolutiony = 0.005;
  49. constexpr float inner_width = 1.2;
  50. constexpr float chassis_height = 0.14;
  51. constexpr float startx = -2.0;
  52. constexpr float starty = -0.1;
  53. constexpr float endx = 2.0;
  54. constexpr float endy = 0.3;
  55. class GridArrayAdapter {
  56. public:
  57. enum {
  58. DATA_DIMENSION = 1
  59. };
  60. explicit GridArrayAdapter(const cv::Mat &grid) : grid_(grid) {}
  61. void GetValue(const int row, const int column, double *const value) const {
  62. if (row < kPadding || column < kPadding || row >= NumRows() - kPadding ||
  63. column >= NumCols() - kPadding) {
  64. *value = kMaxCorrespondenceCost;
  65. } else {
  66. *value = static_cast<double>(grid_.at<float>(row - kPadding, column - kPadding));
  67. }
  68. }
  69. int NumRows() const {
  70. return grid_.rows + 2 * kPadding;
  71. }
  72. int NumCols() const {
  73. return grid_.cols + 2 * kPadding;
  74. }
  75. private:
  76. const cv::Mat &grid_;
  77. };
  78. class chassis_mat_cost {
  79. private:
  80. pcl::PointCloud<pcl::PointXYZ>::Ptr m_cloud; //点云
  81. cv::Mat m_mat;
  82. public:
  83. chassis_mat_cost(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, cv::Mat mat)
  84. : m_cloud(cloud), m_mat(mat) {
  85. }
  86. template<typename T>
  87. bool operator()(const T *const variable, T *residual) const {
  88. T cx = variable[0];
  89. T cy = variable[1];
  90. // T w_ratio = variable[2]/T(inner_width);
  91. // T h_ratio = variable[3]/T(chassis_height);
  92. const GridArrayAdapter adapter(m_mat);
  93. ceres::BiCubicInterpolator<GridArrayAdapter> interpolator(adapter);
  94. //
  95. for (int i = 0; i < m_cloud->size(); ++i) {
  96. //先平移后旋转
  97. const Eigen::Matrix<T, 2, 1> point((T(m_cloud->points[i].x) - cx),
  98. (T(m_cloud->points[i].z) - cy));
  99. T kx = (point(0, 0) - T(startx)) / T(resolutionx) + T(0.5 + kPadding);
  100. T ky = (point(1, 0) - T(starty)) / T(resolutiony) + T(0.5 + kPadding);
  101. interpolator.Evaluate(kx, ky, &residual[i]);
  102. // residual[i] = fx * fy; //+(50./m_cloud->size())/(w*h+1e-16);
  103. }
  104. // residual[m_cloud->size()] = (w_ratio - T(1.0));
  105. // residual[m_cloud->size()+1] = (h_ratio - T(1.0));
  106. return true;
  107. }
  108. // 生成debug图片
  109. void generate_mat(cv::Mat &mat, pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, double *variables) {
  110. mat = m_mat.clone();
  111. // double w_ratio = variables[2] / inner_width;
  112. // double h_ratio = variables[3] / chassis_height;
  113. for (size_t i = 0; i < cloud->size(); i++) {
  114. const Eigen::Vector2d point(
  115. ((cloud->points[i].x - variables[0]) - startx) / resolutionx,
  116. ((cloud->points[i].z - variables[1]) - starty) / resolutiony);
  117. cv::circle(mat, cv::Point2d(point.y(), point.x()), 2, cv::Scalar(0.4), 1);
  118. // std::cout << point.y() << ", " << point.x() << std::endl;
  119. }
  120. }
  121. };
  122. cv::Mat chassis_ceres_solver::m_model = chassis_ceres_solver::create_mat();
  123. chassis_ceres_solver::chassis_ceres_solver() {}
  124. chassis_ceres_solver::~chassis_ceres_solver() {}
  125. /**
  126. * @description: 使用sigmoid函数寻找xoz平面平移以及内宽、底盘高度
  127. */
  128. Error_manager
  129. chassis_ceres_solver::solve(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, double &x, double &y, double &w, double &h) {
  130. double variable[] = {x, y, w, h};
  131. /*printf("init solve x:%.3f y: %.3f wheel:%.3f width:%.3f theta : %.3f front theta: %.3f\n",
  132. variable[0], variable[1], variable[3], variable[4], variable[2], variable[5]);*/
  133. // 第二部分:构建寻优问题
  134. ceres::Problem problem;
  135. chassis_ceres_cost *cost_func = new chassis_ceres_cost(cloud);
  136. //使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个1是输入维度,即待寻优参数x的维度。
  137. ceres::CostFunction *cost_function = new
  138. ceres::AutoDiffCostFunction<chassis_ceres_cost, ceres::DYNAMIC, 4>(
  139. cost_func, cloud->size() + 1);
  140. problem.AddResidualBlock(cost_function, new ceres::HuberLoss(1.0), variable); //向问题中添加误差项,本问题比较简单,添加一个就行。
  141. //第三部分: 配置并运行求解器
  142. ceres::Solver::Options options;
  143. options.use_nonmonotonic_steps = false;
  144. options.linear_solver_type = ceres::DENSE_QR; //配置增量方程的解法
  145. //options.logging_type = ceres::LoggingType::SILENT;
  146. options.max_num_iterations = 500;
  147. options.num_threads = 1;
  148. options.minimizer_progress_to_stdout = false;//输出到cout
  149. ceres::Solver::Summary summary;//优化信息
  150. ceres::Solve(options, &problem, &summary);//求解!!!
  151. double loss = summary.final_cost / (cloud->size());
  152. x = variable[0];
  153. y = variable[1];
  154. w = variable[2];
  155. h = variable[3];
  156. // printf(" loss : %f x:%.5f y:%.5f w:%.5f h:%.5f\n",
  157. // loss,variable[0],variable[1],variable[2],variable[3]);
  158. return SUCCESS;
  159. }
  160. /**
  161. * @description: 图片代替函数十倍提升优化速度
  162. */
  163. Error_manager
  164. chassis_ceres_solver::solve_mat(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, double &x, double &y, double &w, double &h,
  165. bool update_debug_img) {
  166. // std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  167. // create_mat(m_model);
  168. // cv::imshow("model", m_model);
  169. // cv::waitKey(30);
  170. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  171. // std::chrono::duration<double> time_used_mat = std::chrono::duration_cast<std::chrono::duration<double>>(t1 - t0);
  172. double variable[] = {x, y, w, h};
  173. /*printf("init solve x:%.3f y: %.3f wheel:%.3f width:%.3f theta : %.3f front theta: %.3f\n",
  174. variable[0], variable[1], variable[3], variable[4], variable[2], variable[5]);*/
  175. // 第二部分:构建寻优问题
  176. ceres::Problem problem;
  177. chassis_mat_cost *cost_func = new chassis_mat_cost(cloud, m_model);
  178. //使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个1是输入维度,即待寻优参数x的维度。
  179. ceres::CostFunction *cost_function = new
  180. ceres::AutoDiffCostFunction<chassis_mat_cost, ceres::DYNAMIC, 2>(
  181. cost_func, cloud->size());
  182. problem.AddResidualBlock(cost_function, new ceres::HuberLoss(1.0), variable); //向问题中添加误差项,本问题比较简单,添加一个就行。
  183. //第三部分: 配置并运行求解器
  184. ceres::Solver::Options options;
  185. options.use_nonmonotonic_steps = false;
  186. options.linear_solver_type = ceres::DENSE_QR; //配置增量方程的解法
  187. //options.logging_type = ceres::LoggingType::SILENT;
  188. options.max_num_iterations = 500;
  189. options.num_threads = 1;
  190. options.minimizer_progress_to_stdout = false;//输出到cout
  191. ceres::Solver::Summary summary;//优化信息
  192. ceres::Solve(options, &problem, &summary);//求解!!!
  193. // std::cout << summary.BriefReport() << std::endl;
  194. double loss = summary.final_cost / (cloud->size());
  195. x = variable[0];
  196. y = variable[1];
  197. // w = variable[2];
  198. // h = variable[3];
  199. // printf(" loss : %f x:%.5f y:%.5f w:%.5f h:%.5f\n",
  200. // loss,variable[0],variable[1],variable[2],variable[3]);
  201. std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
  202. std::chrono::duration<double> time_used_solve = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);
  203. if (update_debug_img) {
  204. // printf("midx:%.3f, midz:%.3f\n", x, y);
  205. cost_func->generate_mat(m_projected_mat, cloud, variable);
  206. cv::namedWindow("win", cv::WINDOW_FREERATIO);
  207. cv::imshow("win", m_projected_mat);
  208. cv::waitKey();
  209. }
  210. std::chrono::steady_clock::time_point t3 = std::chrono::steady_clock::now();
  211. std::chrono::duration<double> time_used_disp = std::chrono::duration_cast<std::chrono::duration<double>>(t3 - t2);
  212. // std::cout << "\ntime used for solve, display in ms: " << time_used_solve.count() << ", " << time_used_disp.count() << std::endl
  213. // << std::endl;
  214. return SUCCESS;
  215. }
  216. cv::Mat chassis_ceres_solver::create_mat() {
  217. int rows = (endx - startx) / resolutionx + 1;
  218. int cols = (endy - starty) / resolutiony + 1;
  219. if (rows <= 1 || cols <= 1)
  220. return cv::Mat();
  221. cv::Mat t_mat(rows, cols, CV_32FC1);
  222. for (size_t i = 0; i < rows; i++) {
  223. for (size_t j = 0; j < cols; j++) {
  224. double x = i * resolutionx + startx;
  225. double y = j * resolutiony + starty;
  226. double fx = 1.0 / (1.0 + std::exp(-CERES_PA * (x + inner_width / 2.0))) -
  227. 1.0 / (1.0 + std::exp(-CERES_PA * (x - inner_width / 2.0)));
  228. double fy = 1.0 / (1.0 + std::exp(-CERES_PB * (y + chassis_height / 2.0))) -
  229. 1.0 / (1.0 + std::exp(-CERES_PC * (y - chassis_height / 2.0)));
  230. t_mat.at<float>(i, j) = fx * fy;
  231. // std::cout << "x,y: " << x << ", " << y << "-----value: " << 1.0 / (1.0 + std::exp(-CERES_PA * (x + default_width / 2.0)))<<", "<<
  232. // 1.0 / (1.0 + std::exp(-CERES_PA * (x - default_width / 2.0))) << std::endl;
  233. // if(fx*fy>0)
  234. // std::cout << "x,y: " << x << "," << y << ", fx,fy: " << fx << ", " << fy << ", " << fx * fy << std::endl;
  235. }
  236. }
  237. cv::normalize(t_mat, t_mat, 1.0, 0.1, cv::NORM_MINMAX);
  238. // std::cout << t_mat << std::endl;
  239. // cv::namedWindow("win", cv::WINDOW_FREERATIO);
  240. // cv::imshow("win", t_mat);
  241. // cv::waitKey(0);
  242. return t_mat;
  243. }
  244. // 返回投影地图转换的点云, 便于投影到pcl视野中
  245. pcl::PointCloud<pcl::PointXYZ>::Ptr chassis_ceres_solver::get_projected_cloud() {
  246. pcl::PointCloud<pcl::PointXYZ>::Ptr t_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(
  247. new pcl::PointCloud<pcl::PointXYZ>);
  248. if (m_projected_mat.empty())
  249. return t_cloud;
  250. for (size_t i = 0; i < m_projected_mat.rows; i++) {
  251. for (size_t j = 0; j < m_projected_mat.cols; j++) {
  252. double x0 = (i * resolutionx + startx);
  253. t_cloud->push_back(pcl::PointXYZ());
  254. }
  255. }
  256. return t_cloud;
  257. }