detect_wheel_ceres3d.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. //
  2. // Created by zx on 2020/7/1.
  3. //
  4. #include "detect_wheel_ceres3d.h"
  5. #include "interpolated_grid.hpp"
  6. #include <pcl/common/transforms.h>
  7. #include "tool/point_tool.h"
  8. class CostFunctor3d
  9. {
  10. private:
  11. const InterpolatedProbabilityGrid m_left_interpolated_grid;
  12. const InterpolatedProbabilityGrid m_right_interpolated_grid;
  13. mutable double m_costs_lf, m_costs_rf, m_costs_lr, m_costs_rr;
  14. pcl::PointCloud<pcl::PointXYZ> m_left_front_cloud; //左前点云
  15. pcl::PointCloud<pcl::PointXYZ> m_right_front_cloud; //右前点云
  16. pcl::PointCloud<pcl::PointXYZ> m_left_rear_cloud; //左后点云
  17. pcl::PointCloud<pcl::PointXYZ> m_right_rear_cloud; //右后点云
  18. // 20220118 added by yct
  19. float m_ratio; // 模型变换比例,用于贴合模型,cloud / ratio --> model
  20. public:
  21. CostFunctor3d(pcl::PointCloud<pcl::PointXYZ> left_front, pcl::PointCloud<pcl::PointXYZ> right_front,
  22. pcl::PointCloud<pcl::PointXYZ> left_rear, pcl::PointCloud<pcl::PointXYZ> right_rear,
  23. const HybridGrid& left_interpolated_grid,
  24. const HybridGrid& right_interpolated_grid, float ratio)
  25. :m_left_interpolated_grid(left_interpolated_grid),m_right_interpolated_grid(right_interpolated_grid)
  26. {
  27. m_left_front_cloud = left_front;
  28. m_right_front_cloud = right_front;
  29. m_left_rear_cloud = left_rear;
  30. m_right_rear_cloud = right_rear;
  31. m_costs_lf = 0.0;
  32. m_costs_rf = 0.0;
  33. m_costs_lr = 0.0;
  34. m_costs_rr = 0.0;
  35. m_ratio = ratio;
  36. }
  37. template<typename T>
  38. bool operator()(const T *const variable, T *residual) const
  39. {
  40. T cx = variable[0];
  41. T cy = variable[1];
  42. T theta = variable[2];
  43. T length = variable[3];
  44. T width = variable[4];
  45. T theta_front = variable[5];
  46. T lf_z = variable[6];
  47. T lr_z = variable[7];
  48. T rf_z = variable[8];
  49. T rr_z = variable[9];
  50. // T lf_z = T(0);
  51. // T lr_z = T(0);
  52. // T rf_z = T(0);
  53. // T rr_z = T(0);
  54. //整车旋转
  55. Eigen::Rotation2D<T> rotation(theta);
  56. Eigen::Matrix<T, 2, 2> rotation_matrix = rotation.toRotationMatrix();
  57. //左前偏移
  58. Eigen::Matrix<T, 2, 1> wheel_center_normal_left_front(length / 2.0, width / 2.0);
  59. //右前偏移
  60. Eigen::Matrix<T, 2, 1> wheel_center_normal_right_front(length / 2.0, -width / 2.0);
  61. //左后偏移
  62. Eigen::Matrix<T, 2, 1> wheel_center_normal_left_rear(-length / 2.0, width / 2.0);
  63. //右后偏移
  64. Eigen::Matrix<T, 2, 1> wheel_center_normal_right_rear(-length / 2.0, -width / 2.0);
  65. //前轮旋转
  66. Eigen::Rotation2D<T> rotation_front(theta_front);
  67. Eigen::Matrix<T, 2, 2> rotation_matrix_front = rotation_front.toRotationMatrix();
  68. //左前轮
  69. int left_front_num = m_left_front_cloud.size();
  70. for (int i = 0; i < m_left_front_cloud.size(); ++i)
  71. {
  72. const Eigen::Matrix<T, 2, 1> point((T(m_left_front_cloud[i].x) - cx),
  73. (T(m_left_front_cloud[i].y) - cy));
  74. //减去经过车辆旋转计算的左前中心
  75. const Eigen::Matrix<T, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_left_front;
  76. //旋转
  77. const Eigen::Matrix<T, 2, 1> point_rotation = rotation_matrix_front * (tanslate_point*T(m_ratio));
  78. residual[i] = T(1.0) - m_left_interpolated_grid.GetInterpolatedValue(point_rotation[0],point_rotation[1],
  79. T(m_left_front_cloud[i].z) + lf_z);
  80. }
  81. //右前轮
  82. int right_front_num = m_right_front_cloud.size();
  83. for (int i = 0; i < m_right_front_cloud.size(); ++i)
  84. {
  85. const Eigen::Matrix<T, 2, 1> point((T(m_right_front_cloud[i].x) - cx),
  86. (T(m_right_front_cloud[i].y) - cy));
  87. //减去经过车辆旋转计算的左前中心
  88. const Eigen::Matrix<T, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_right_front;
  89. //旋转
  90. const Eigen::Matrix<T, 2, 1> point_rotation = rotation_matrix_front * (tanslate_point*T(m_ratio));
  91. residual[left_front_num + i] = T(1.0) - m_right_interpolated_grid.GetInterpolatedValue(point_rotation[0],point_rotation[1],
  92. T(m_right_front_cloud[i].z) + rf_z);
  93. }
  94. //左后轮
  95. int left_rear_num = m_left_rear_cloud.size();
  96. for (int i = 0; i < m_left_rear_cloud.size(); ++i)
  97. {
  98. const Eigen::Matrix<T, 2, 1> point((T(m_left_rear_cloud[i].x) - cx),
  99. (T(m_left_rear_cloud[i].y) - cy));
  100. //减去经过车辆旋转计算的左前中心
  101. const Eigen::Matrix<T, 2, 1> tanslate_point = (rotation_matrix * point - wheel_center_normal_left_rear)*T(m_ratio);;
  102. residual[left_front_num + right_front_num + i] = T(1.0) -
  103. m_left_interpolated_grid.GetInterpolatedValue(tanslate_point[0],tanslate_point[1],
  104. T(m_left_rear_cloud[i].z) + lr_z);
  105. }
  106. //右后轮
  107. int right_rear_num = m_right_rear_cloud.size();
  108. for (int i = 0; i < m_right_rear_cloud.size(); ++i)
  109. {
  110. const Eigen::Matrix<T, 2, 1> point((T(m_right_rear_cloud[i].x) - cx),
  111. (T(m_right_rear_cloud[i].y) - cy));
  112. //减去经过车辆旋转计算的左前中心
  113. const Eigen::Matrix<T, 2, 1> tanslate_point = (rotation_matrix * point - wheel_center_normal_right_rear)*T(m_ratio);
  114. residual[left_front_num + right_front_num + left_rear_num+i] = T(1.0) -
  115. m_right_interpolated_grid.GetInterpolatedValue(tanslate_point[0],tanslate_point[1],
  116. T(m_right_rear_cloud[i].z) + rr_z);
  117. }
  118. return true;
  119. }
  120. };
  121. detect_wheel_ceres3d::detect_wheel_ceres3d(pcl::PointCloud<pcl::PointXYZ>::Ptr left_grid_cloud,
  122. pcl::PointCloud<pcl::PointXYZ>::Ptr right_grid_cloud)
  123. {
  124. m_left_model_cloud.clear();
  125. m_right_model_cloud.clear();
  126. m_left_model_cloud += *left_grid_cloud;
  127. m_right_model_cloud += *right_grid_cloud;
  128. mp_left_grid = WheelModel3D::iter()->left_grid();
  129. mp_right_grid = WheelModel3D::iter()->right_grid();
  130. // mp_left_grid = nullptr;
  131. // mp_right_grid = nullptr;
  132. // update_model();
  133. // DLOG(INFO) <<"init model end";
  134. // save_model(ETC_PATH"MeasureNode/feature_extra");
  135. }
  136. // 根据点云与模型比例参数更新模型
  137. bool detect_wheel_ceres3d::update_model(float ratio)
  138. {
  139. float del_x=0.05;
  140. float del_y=0.03;
  141. float del_z=0.05;
  142. Eigen::Matrix3f delta=Eigen::MatrixXf::Identity(3,3);
  143. delta(0,0)=del_x*del_x;
  144. delta(1,1)=del_y*del_y;
  145. delta(2,2)=del_z*del_z;
  146. Eigen::Matrix3f delta_inv=delta.inverse();
  147. Eigen::Vector3f d(0,0,0.02);
  148. Eigen::MatrixXf ce=-0.5*((d).transpose()*delta_inv*(d));
  149. float cut_p=exp(ce(0,0));
  150. // std::cout << "1111" << std::endl;
  151. float resolution=0.01;
  152. if(mp_left_grid!=nullptr){
  153. delete mp_left_grid;
  154. mp_left_grid = nullptr;
  155. }
  156. if(mp_right_grid != nullptr){
  157. delete mp_right_grid;
  158. mp_right_grid = nullptr;
  159. }
  160. mp_left_grid=new HybridGrid(resolution);
  161. mp_right_grid=new HybridGrid(resolution);
  162. // 变换模型点云
  163. pcl::PointCloud<pcl::PointXYZ> t_left_model;
  164. t_left_model += m_left_model_cloud;
  165. pcl::PointCloud<pcl::PointXYZ> t_right_model;
  166. t_right_model += m_right_model_cloud;
  167. for (size_t i = 0; i < t_left_model.size(); i++)
  168. {
  169. t_left_model[i].x = t_left_model[i].x * ratio;
  170. t_left_model[i].y = t_left_model[i].y * ratio;
  171. t_left_model[i].z = t_left_model[i].z * ratio;
  172. }
  173. for (size_t i = 0; i < t_right_model.size(); i++)
  174. {
  175. t_right_model[i].x = t_right_model[i].x * ratio;
  176. t_right_model[i].y = t_right_model[i].y * ratio;
  177. t_right_model[i].z = t_right_model[i].z * ratio;
  178. }
  179. for(int i=0;i<t_left_model.size();++i)
  180. {
  181. pcl::PointXYZ pt=t_left_model[i];
  182. Eigen::Vector3f u(pt.x,pt.y,pt.z);
  183. DLOG(INFO) << " ------------------------------------------------------------------------------------------------- "<< this;
  184. for(float x=pt.x-0.1;x<pt.x+0.1;x+=mp_left_grid->resolution())
  185. {
  186. for(float y=pt.y-0.1;y<pt.y+0.1;y+=mp_left_grid->resolution())
  187. {
  188. for(float z=pt.z-0.1;z<pt.z+0.1;z+=mp_left_grid->resolution())
  189. {
  190. Eigen::Vector3f p(x,y,z);
  191. Eigen::MatrixXf B=-0.5*((p-u).transpose()*delta_inv*(p-u));
  192. float prob=exp(B(0,0));
  193. if(prob>cut_p)
  194. prob=cut_p;
  195. Eigen::Array3i index=mp_left_grid->GetCellIndex(p);
  196. if(mp_left_grid->GetProbability(index)<prob){
  197. mp_left_grid->SetProbability(index,prob);
  198. }
  199. }
  200. }
  201. }
  202. }
  203. // std::cout << "3333" << std::endl;
  204. for(int i=0;i<t_right_model.size();++i)
  205. {
  206. pcl::PointXYZ pt=t_right_model[i];
  207. Eigen::Vector3f u(pt.x,pt.y,pt.z);
  208. for(float x=pt.x-0.1;x<pt.x+0.1;x+=mp_right_grid->resolution())
  209. {
  210. for(float y=pt.y-0.1;y<pt.y+0.1;y+=mp_right_grid->resolution())
  211. {
  212. for(float z=pt.z-0.1;z<pt.z+0.1;z+=mp_right_grid->resolution())
  213. {
  214. Eigen::Vector3f p(x,y,z);
  215. Eigen::MatrixXf B=-0.5*((p-u).transpose()*delta_inv*(p-u));
  216. float prob=exp(B(0,0));
  217. if(prob>cut_p)
  218. prob=cut_p;
  219. Eigen::Array3i index=mp_right_grid->GetCellIndex(p);
  220. if(mp_right_grid->GetProbability(index)<prob)
  221. mp_right_grid->SetProbability(index,prob);
  222. }
  223. }
  224. }
  225. }
  226. return true;
  227. }
  228. void detect_wheel_ceres3d::save_model(std::string dir)
  229. {
  230. InterpolatedProbabilityGrid inter_grid(*mp_left_grid);
  231. pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_grid(new pcl::PointCloud<pcl::PointXYZRGB>);
  232. for(int x=0;x<mp_left_grid->grid_size();++x)
  233. {
  234. for(int y=0;y<mp_left_grid->grid_size();++y)
  235. {
  236. for(int z=0;z<mp_left_grid->grid_size();++z)
  237. {
  238. Eigen::Array3i index(x-mp_left_grid->grid_size()/2,
  239. y-mp_left_grid->grid_size()/2,z-mp_left_grid->grid_size()/2);
  240. Eigen::Vector3f pt=mp_left_grid->GetCenterOfCell(index);
  241. float prob=inter_grid.GetInterpolatedValue(double(pt[0]),double(pt[1]),double(pt[2]));
  242. if(prob>0.01)
  243. {
  244. Eigen::Vector3f pt=mp_left_grid->GetCenterOfCell(index);
  245. int rgb=int((prob-0.01)*255);
  246. pcl::PointXYZRGB point;
  247. point.x=pt[0];
  248. point.y=pt[1];
  249. point.z=pt[2];
  250. point.r=rgb;
  251. point.g=0;
  252. point.b=255-rgb;
  253. cloud_grid->push_back(point);
  254. }
  255. }
  256. }
  257. }
  258. InterpolatedProbabilityGrid right_grid(*mp_right_grid);
  259. pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_right_grid(new pcl::PointCloud<pcl::PointXYZRGB>);
  260. for(int x=0;x<mp_right_grid->grid_size();++x)
  261. {
  262. for(int y=0;y<mp_right_grid->grid_size();++y)
  263. {
  264. for(int z=0;z<mp_right_grid->grid_size();++z)
  265. {
  266. Eigen::Array3i index(x-mp_right_grid->grid_size()/2,
  267. y-mp_right_grid->grid_size()/2,z-mp_right_grid->grid_size()/2);
  268. Eigen::Vector3f pt=mp_right_grid->GetCenterOfCell(index);
  269. float prob=right_grid.GetInterpolatedValue(double(pt[0]),double(pt[1]),double(pt[2]));
  270. if(prob>0.01)
  271. {
  272. Eigen::Vector3f pt=mp_right_grid->GetCenterOfCell(index);
  273. int rgb=int((prob-0.01)*255);
  274. pcl::PointXYZRGB point;
  275. point.x=pt[0];
  276. point.y=pt[1];
  277. point.z=pt[2];
  278. point.r=rgb;
  279. point.g=0;
  280. point.b=255-rgb;
  281. cloud_right_grid->push_back(point);
  282. }
  283. }
  284. }
  285. }
  286. // std::cout<<" save model :"<<dir<<std::endl;
  287. // save_cloud_txt(cloud_grid,dir+"/left_model.txt");
  288. // save_cloud_txt(cloud_right_grid,dir+"/right_model.txt");
  289. // exit(EXIT_FAILURE);
  290. }
  291. detect_wheel_ceres3d::~detect_wheel_ceres3d(){
  292. delete mp_left_grid;
  293. delete mp_right_grid;
  294. mp_left_grid= nullptr;
  295. mp_right_grid= nullptr;
  296. }
  297. bool detect_wheel_ceres3d::detect(std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> cloud_vec,
  298. Detect_result &detect_result, std::string &error_info)
  299. {
  300. error_info = "";
  301. //清理点云
  302. m_left_front_cloud.clear();
  303. m_right_front_cloud.clear();
  304. m_left_rear_cloud.clear();
  305. m_right_rear_cloud.clear();
  306. //重新计算点云,按方位分割
  307. //第一步,计算整体中心,主轴方向
  308. pcl::PointCloud<pcl::PointXYZ> cloud_all;
  309. for (int i = 0; i < cloud_vec.size(); ++i)
  310. {
  311. cloud_all += (*cloud_vec[i]);
  312. }
  313. // std::cout<<"cloud size: "<<cloud_all.size()<<std::endl;
  314. if (cloud_all.size() < 20)
  315. return false;
  316. Eigen::Vector4f centroid;
  317. pcl::compute3DCentroid(cloud_all, centroid);
  318. double center_x = centroid[0];
  319. double center_y = centroid[1];
  320. // printf("3dwheel x,y:%.3f, %.3f\n", center_x, center_y);
  321. // save_cloud_txt(cloud_all.makeShared(), "total_wheel.txt");
  322. //计算外接旋转矩形
  323. std::vector<cv::Point2f> points_cv;
  324. for (int i = 0; i < cloud_all.size(); ++i)
  325. {
  326. points_cv.push_back(cv::Point2f(cloud_all[i].x, cloud_all[i].y));
  327. }
  328. cv::RotatedRect rotate_rect = cv::minAreaRect(points_cv);
  329. //计算旋转矩形与X轴的夹角
  330. cv::Point2f vec;
  331. cv::Point2f vertice[4];
  332. rotate_rect.points(vertice);
  333. float len1 = pow(vertice[0].x - vertice[1].x, 2.0) + pow(vertice[0].y - vertice[1].y, 2.0);
  334. float len2 = pow(vertice[1].x - vertice[2].x, 2.0) + pow(vertice[1].y - vertice[2].y, 2.0);
  335. // 寻找长边,倾角为长边与x轴夹角
  336. if (len1 > len2)
  337. {
  338. vec.x = vertice[0].x - vertice[1].x;
  339. vec.y = vertice[0].y - vertice[1].y;
  340. }
  341. else
  342. {
  343. vec.x = vertice[1].x - vertice[2].x;
  344. vec.y = vertice[1].y - vertice[2].y;
  345. }
  346. float angle_x = 180.0 / M_PI * acos(vec.x / sqrt(vec.x * vec.x + vec.y * vec.y));
  347. // printf("rect theta: %.3f\n",angle_x);
  348. // 20211203 added by yct, 初始xy不准确,逻辑调整
  349. pcl::PointCloud<pcl::PointXYZ> t_cloud_left, t_cloud_right, t_cloud_front, t_cloud_rear;
  350. //第二步, 将每份点云旋转回去,计算点云重心所在象限
  351. for (int i = 0; i < cloud_vec.size(); ++i)
  352. {
  353. pcl::PointCloud<pcl::PointXYZ> cloud = (*cloud_vec[i]);
  354. Eigen::Affine3f traslation = Eigen::Affine3f::Identity();//初始化变换矩阵为单位矩阵
  355. // 平移
  356. traslation.translation() << -center_x, -center_y, 0.0;
  357. pcl::PointCloud<pcl::PointXYZ> translate_cloud;
  358. pcl::transformPointCloud(cloud, translate_cloud, traslation);
  359. // 旋转; Z 轴上旋转angle_x 弧度,Y轴上旋转0弧度
  360. Eigen::Affine3f rotation = Eigen::Affine3f::Identity();
  361. rotation.rotate(Eigen::AngleAxisf(-angle_x * M_PI / 180.0, Eigen::Vector3f::UnitZ()));
  362. pcl::PointCloud<pcl::PointXYZ> transformed_cloud;
  363. pcl::transformPointCloud(translate_cloud, transformed_cloud, rotation);
  364. //计算重心
  365. Eigen::Vector4f centroid;
  366. pcl::compute3DCentroid(transformed_cloud, centroid);
  367. double x = centroid[0];
  368. double y = centroid[1];
  369. //计算象限
  370. if (x > 0 && y > 0)
  371. {
  372. //第一象限
  373. m_left_front_cloud = cloud;
  374. t_cloud_left+=(m_left_front_cloud);
  375. t_cloud_front+=(m_left_front_cloud);
  376. }
  377. if (x > 0 && y < 0)
  378. {
  379. //第四象限
  380. m_right_front_cloud = cloud;
  381. t_cloud_right+=(m_right_front_cloud);
  382. t_cloud_front+=(m_right_front_cloud);
  383. }
  384. if (x < 0 && y > 0)
  385. {
  386. //第二象限
  387. m_left_rear_cloud = cloud;
  388. t_cloud_left+=(m_left_rear_cloud);
  389. t_cloud_rear+=(m_left_rear_cloud);
  390. }
  391. if (x < 0 && y < 0)
  392. {
  393. //第三象限
  394. m_right_rear_cloud = cloud;
  395. t_cloud_right+=(m_right_rear_cloud);
  396. t_cloud_rear+=(m_right_rear_cloud);
  397. }
  398. }
  399. // 20211203 added by yct, 重新计算xy
  400. Eigen::Vector4f centroid_left,centroid_right,centroid_front,centroid_rear;
  401. // 计算x
  402. pcl::compute3DCentroid(t_cloud_left, centroid_left);
  403. pcl::compute3DCentroid(t_cloud_right, centroid_right);
  404. // 计算y
  405. pcl::compute3DCentroid(t_cloud_front, centroid_front);
  406. pcl::compute3DCentroid(t_cloud_rear, centroid_rear);
  407. // LOG(WARNING)<<"x,y: "<<(centroid_left.x()+centroid_right.x())/2.0f<<", "<<(centroid_front.y()+centroid_rear.y())/2.0f;
  408. // 使用外部第一步优化产生的x,以及当前计算后的y作为初值
  409. // 多次优化,获取最佳优化结果
  410. detect_result.cx = detect_result.cx;
  411. detect_result.cy = (centroid_front.y()+centroid_rear.y())/2.0f;
  412. detect_result.wheel_base = centroid_front.y() - centroid_rear.y() + 0.12; //std::max(len1,len2);
  413. // 已计算次数,初始传入值正常,之后solve函数会修改初始值,需要恢复角度单位为弧度
  414. int calc_count = 0;
  415. // double final_theta = 0;
  416. // 误差结构体,保存左前、右前、左后、右后、整体平均误差
  417. Loss_result loss_result;
  418. // 平均误差值,用于获取最小整体平均误差
  419. double avg_loss = 100;
  420. // 定义图像列数,控制图像大小
  421. int map_cols = 800;
  422. // 优化后图像行数,用于保存优化后结果图像
  423. int optimized_map_rows = 200;
  424. // 优化结果
  425. bool solve_result = false;
  426. double total_solve_time = 0;
  427. bool stop_sign = false;
  428. Detect_result t_detect_result = detect_result;
  429. // 寻找最小loss值对应的初始旋转角
  430. // LOG(WARNING) <<cloud_all.size()<< ", car angle: "<<t_detect_result.theta<<", "<<(-angle_x ) * M_PI / 180.0;
  431. // t_detect_result.theta = (-angle_x ) * M_PI / 180.0;
  432. Loss_result t_loss_result;
  433. t_loss_result.total_avg_loss = 1000;
  434. //输出角度已变化,需恢复成弧度
  435. if (calc_count > 0)
  436. {
  437. t_detect_result.front_theta *= (-M_PI) / 180.0;
  438. }
  439. std::string t_error_info;
  440. bool current_result = Solve(t_detect_result, t_loss_result, t_error_info);
  441. error_info = t_error_info;
  442. // std::cout<<"current_result: "<<current_result<<std::endl;
  443. if (current_result)
  444. {
  445. avg_loss = t_loss_result.total_avg_loss;
  446. // final_theta = -input_vars[2] * M_PI / 180.0;
  447. detect_result = t_detect_result;
  448. detect_result.loss = t_loss_result;
  449. solve_result = current_result;
  450. loss_result = t_loss_result;
  451. }
  452. detect_result.success = solve_result;
  453. return solve_result;
  454. }
  455. // 将点云数据根据costFunction函数的求解进行求解,获取各个轮子的losses值
  456. void detect_wheel_ceres3d::get_costs(double* variable,double &lf, double &rf, double &lr, double &rr)
  457. {
  458. double losses[4]={0};
  459. double cx = variable[0];
  460. double cy = variable[1];
  461. double theta = variable[2];
  462. double length = variable[3];
  463. double width = variable[4];
  464. double theta_front = variable[5];
  465. double lf_z = variable[6];
  466. double lr_z = variable[7];
  467. double rf_z = variable[8];
  468. double rr_z = variable[9];
  469. //整车旋转
  470. Eigen::Rotation2D<double> rotation(theta);
  471. Eigen::Matrix<double, 2, 2> rotation_matrix = rotation.toRotationMatrix();
  472. //左前偏移
  473. Eigen::Matrix<double, 2, 1> wheel_center_normal_left_front(length / 2.0, width / 2.0);
  474. //右前偏移
  475. Eigen::Matrix<double, 2, 1> wheel_center_normal_right_front(length / 2.0, -width / 2.0);
  476. //左后偏移
  477. Eigen::Matrix<double, 2, 1> wheel_center_normal_left_rear(-length / 2.0, width / 2.0);
  478. //右后偏移
  479. Eigen::Matrix<double, 2, 1> wheel_center_normal_right_rear(-length / 2.0, -width / 2.0);
  480. //前轮旋转
  481. Eigen::Rotation2D<double> rotation_front(theta_front);
  482. Eigen::Matrix<double, 2, 2> rotation_matrix_front = rotation_front.toRotationMatrix();
  483. InterpolatedProbabilityGrid left_interpolated_grid(*mp_left_grid);
  484. InterpolatedProbabilityGrid right_interpolated_grid(*mp_right_grid);
  485. //左前轮
  486. int left_front_num = m_left_front_cloud.size();
  487. m_left_front_transformed_cloud.clear();
  488. for (int i = 0; i < m_left_front_cloud.size(); ++i)
  489. {
  490. const Eigen::Matrix<double, 2, 1> point((double(m_left_front_cloud[i].x) - cx),
  491. (double(m_left_front_cloud[i].y) - cy));
  492. //减去经过车辆旋转计算的左前中心
  493. const Eigen::Matrix<double, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_left_front;
  494. //旋转
  495. const Eigen::Matrix<double, 2, 1> point_rotation = rotation_matrix_front * tanslate_point;
  496. losses[0] += 1.0 - left_interpolated_grid.GetInterpolatedValue(point_rotation[0],point_rotation[1],
  497. double(m_left_front_cloud[i].z) + lf_z);
  498. m_left_front_transformed_cloud.push_back(pcl::PointXYZ(point_rotation[0],point_rotation[1],m_left_front_cloud[i].z));
  499. }
  500. //右前轮
  501. int right_front_num = m_right_front_cloud.size();
  502. m_right_front_transformed_cloud.clear();
  503. for (int i = 0; i < m_right_front_cloud.size(); ++i)
  504. {
  505. const Eigen::Matrix<double, 2, 1> point((double(m_right_front_cloud[i].x) - cx),
  506. (double(m_right_front_cloud[i].y) - cy));
  507. //减去经过车辆旋转计算的左前中心
  508. const Eigen::Matrix<double, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_right_front;
  509. //旋转
  510. const Eigen::Matrix<double, 2, 1> point_rotation = rotation_matrix_front * tanslate_point;
  511. losses[1]+= 1.0 - right_interpolated_grid.GetInterpolatedValue(point_rotation[0],point_rotation[1],
  512. double(m_right_front_cloud[i].z));
  513. m_right_front_transformed_cloud.push_back(pcl::PointXYZ(point_rotation[0],point_rotation[1],
  514. double(m_right_front_cloud[i].z) + rf_z));
  515. }
  516. //左后轮
  517. int left_rear_num = m_left_rear_cloud.size();
  518. m_left_rear_transformed_cloud.clear();
  519. for (int i = 0; i < m_left_rear_cloud.size(); ++i)
  520. {
  521. const Eigen::Matrix<double, 2, 1> point((double(m_left_rear_cloud[i].x) - cx),
  522. (double(m_left_rear_cloud[i].y) - cy));
  523. //减去经过车辆旋转计算的左前中心
  524. const Eigen::Matrix<double, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_left_rear;
  525. losses[2] += 1.0 -
  526. left_interpolated_grid.GetInterpolatedValue(tanslate_point[0],tanslate_point[1],
  527. double(m_left_rear_cloud[i].z));
  528. m_left_rear_transformed_cloud.push_back(pcl::PointXYZ(tanslate_point[0],tanslate_point[1],
  529. double(m_left_rear_cloud[i].z) + lr_z));
  530. }
  531. //右后轮
  532. int right_rear_num = m_right_rear_cloud.size();
  533. m_right_rear_transformed_cloud.clear();
  534. for (int i = 0; i < m_right_rear_cloud.size(); ++i)
  535. {
  536. const Eigen::Matrix<double, 2, 1> point((double(m_right_rear_cloud[i].x) - cx),
  537. (double(m_right_rear_cloud[i].y) - cy));
  538. //减去经过车辆旋转计算的左前中心
  539. const Eigen::Matrix<double, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_right_rear;
  540. losses[3]+= 1.0 -
  541. right_interpolated_grid.GetInterpolatedValue(tanslate_point[0],tanslate_point[1],
  542. double(m_right_rear_cloud[i].z));
  543. m_right_rear_transformed_cloud.push_back(pcl::PointXYZ(tanslate_point[0],tanslate_point[1],
  544. double(m_right_rear_cloud[i].z) + rr_z));
  545. }
  546. lf = losses[0];
  547. rf = losses[1];
  548. lr = losses[2];
  549. rr = losses[3];
  550. }
  551. void detect_wheel_ceres3d::save_debug_data(std::string dir )
  552. {
  553. ::save_cloud_txt(m_left_front_transformed_cloud.makeShared(),dir+"/left_front_tranformed.txt");
  554. ::save_cloud_txt(m_right_front_transformed_cloud.makeShared(),dir+"/right_front_tranformed.txt");
  555. ::save_cloud_txt(m_left_rear_transformed_cloud.makeShared(),dir+"/left_rear_tranformed.txt");
  556. ::save_cloud_txt(m_right_rear_transformed_cloud.makeShared(),dir+"/right_rear_tranformed.txt");
  557. }
  558. // 外接矩形估算车轮宽度,以此调整模型比例
  559. bool detect_wheel_ceres3d::wheel_size_estimate(double &wheel_width, double &wheel_length, double car_angle, float &ratio)
  560. {
  561. // 分别对四轮寻找外接矩形
  562. int rect_res = 0;
  563. cv::RotatedRect rects[4]; // t_left_front_rect, t_right_front_rect, t_left_rear_rect, t_right_rear_rect;
  564. double rot_angles[4], lengths[4], widths[4];
  565. rect_res += get_wheel_rect(m_left_front_cloud, rects[0], rot_angles[0], lengths[0], widths[0]) ? 0 : 1;
  566. rect_res += get_wheel_rect(m_right_front_cloud, rects[1], rot_angles[1], lengths[1], widths[1]) ? 0 : 1;
  567. rect_res += get_wheel_rect(m_left_rear_cloud, rects[2], rot_angles[2], lengths[2], widths[2]) ? 0 : 1;
  568. rect_res += get_wheel_rect(m_right_rear_cloud, rects[3], rot_angles[3], lengths[3], widths[3]) ? 0 : 1;
  569. // 只允许一个异常轮胎
  570. if(rect_res > 1)
  571. {
  572. // std::cout << "异常轮胎过多 " << rect_res << std::endl;
  573. return false;
  574. }
  575. // 计算轮宽
  576. double avg_width = 0.0;
  577. double avg_length = 0.0;
  578. for (size_t i = 2; i < 4; i++)
  579. {
  580. avg_width += widths[i];
  581. avg_length += lengths[i];
  582. }
  583. avg_width /= 2.0;
  584. avg_length /= 2.0;
  585. // std::cout << "avg width: " << avg_width << ", avg length: " << avg_length << std::endl;
  586. // 以投影方式计算轮宽
  587. Eigen::Vector2d car_angle_vec(cos(-car_angle), sin(-car_angle));
  588. double left_min=INT_MAX, left_max=-INT_MAX, right_min=INT_MAX, right_max=-INT_MAX;
  589. if(m_left_rear_cloud.size()==0 || m_right_rear_cloud.size()==0)
  590. {
  591. ratio = 1.0f;
  592. return false;
  593. }
  594. for (size_t i = 0; i < m_left_rear_cloud.size(); i++)
  595. {
  596. Eigen::Vector2d point_vec(m_left_rear_cloud[i].x, m_left_rear_cloud[i].y);
  597. double res = sqrt(point_vec.squaredNorm() - pow(car_angle_vec.dot(point_vec),2));
  598. // std::cout<<"lres: "<<res<<std::endl;
  599. if(res<left_min)
  600. left_min=res;
  601. if(res>left_max)
  602. left_max=res;
  603. }
  604. for (size_t i = 0; i < m_right_rear_cloud.size(); i++)
  605. {
  606. Eigen::Vector2d point_vec(m_right_rear_cloud[i].x, m_right_rear_cloud[i].y);
  607. double res = sqrt(point_vec.squaredNorm() - pow(car_angle_vec.dot(point_vec),2));
  608. // std::cout<<"rres: "<<res<<std::endl;
  609. if(res<right_min)
  610. right_min=res;
  611. if(res>right_max)
  612. right_max=res;
  613. }
  614. double new_wheel_width = (left_max+right_max-left_min-right_min)/2.0;
  615. // std::cout << "avg width: " << avg_width << ", new width: " << new_wheel_width << std::endl;
  616. wheel_width = new_wheel_width;
  617. wheel_length = avg_length;
  618. // ratio = 1.0f;
  619. // 轮宽范围,实际0.185-0.3,通常会少0.03-0.04,(新方法不会少),因此设定范围0.175-0.275
  620. // 比例以半径0.64为模板,范围0.6-0.7
  621. if(wheel_width<0.18||wheel_width>0.3)
  622. {
  623. ratio = 1.0f;
  624. }else{
  625. float t_model_ratio = float((0.6 + ((wheel_width - 0.175) * 0.1 / 0.1)) / 0.64);
  626. t_model_ratio = std::max(0.6f/0.64f, t_model_ratio);
  627. t_model_ratio = std::min(0.7f/0.64f, t_model_ratio);
  628. ratio = 1.0f / t_model_ratio;
  629. }
  630. return true;
  631. }
  632. // 使用外接矩形,车轮越大,多条线照到车轮的概率与车轮半径都越大,导致外接矩形向内侧收拢的趋势更明显,轴距偏小得越厉害
  633. bool detect_wheel_ceres3d::wheebase_estimate(double &wheelbase, double &wheel_width, double &wheel_length)
  634. {
  635. // 分别对四轮寻找外接矩形
  636. int rect_res = 0;
  637. cv::RotatedRect rects[4]; // t_left_front_rect, t_right_front_rect, t_left_rear_rect, t_right_rear_rect;
  638. double rot_angles[4], lengths[4], widths[4];
  639. rect_res += get_wheel_rect(m_left_front_cloud, rects[0], rot_angles[0], lengths[0], widths[0]) ? 0 : 1;
  640. rect_res += get_wheel_rect(m_right_front_cloud, rects[1], rot_angles[1], lengths[1], widths[1]) ? 0 : 1;
  641. rect_res += get_wheel_rect(m_left_rear_cloud, rects[2], rot_angles[2], lengths[2], widths[2]) ? 0 : 1;
  642. rect_res += get_wheel_rect(m_right_rear_cloud, rects[3], rot_angles[3], lengths[3], widths[3]) ? 0 : 1;
  643. // 只允许一个异常轮胎
  644. if(rect_res > 1)
  645. {
  646. // std::cout << "异常轮胎过多 " << rect_res << std::endl;
  647. return false;
  648. }
  649. // 只用后轮计算轮宽
  650. double avg_width = 0.0;
  651. double avg_length = 0.0;
  652. for (size_t i = 2; i < 4; i++)
  653. {
  654. avg_width += widths[i];
  655. avg_length += lengths[i];
  656. }
  657. avg_width /= 2.0;
  658. avg_length /= 2.0;
  659. // std::cout << "avg width: " << avg_width << ", avg length: " << avg_length << std::endl;
  660. wheel_width = avg_width;
  661. wheel_length = avg_length;
  662. // 检查角度,后轮不可超过5度,前轮不可超过30度
  663. int rear_limit_count = 0, front_limit_count = 0;
  664. int rear_abnormal_index = -1, front_abnormal_index = -1;
  665. for (size_t i = 2; i < 4; i++)
  666. {
  667. if (90-rot_angles[i] > 5)
  668. {
  669. // std::cout << "后轮角度 " << rot_angles[i] << std::endl;
  670. rear_limit_count++;
  671. rear_abnormal_index = i;
  672. }
  673. // else
  674. // {
  675. // // 后轮记录
  676. // rear_index = i;
  677. // }
  678. }
  679. for (size_t i = 0; i < 2; i++)
  680. {
  681. if (90-rot_angles[i] > 30)
  682. {
  683. // std::cout << "前轮角度 " << rot_angles[i] << std::endl;
  684. front_limit_count++;
  685. front_abnormal_index = i;
  686. }
  687. // else
  688. // {
  689. // // 前轮记录
  690. // front_index = i;
  691. // }
  692. }
  693. // 异常矩形超过一个
  694. if (rear_limit_count + front_limit_count > 1)
  695. {
  696. // std::cout << "异常矩形过多 " << rear_limit_count<<", "<<front_limit_count << std::endl;
  697. return false;
  698. }
  699. // 剔除可能异常数据,计算轴距
  700. Eigen::Vector2d wb_vector;
  701. if (rear_abnormal_index != 2 && front_abnormal_index != 0)
  702. {
  703. wb_vector << rects[0].center.x - rects[2].center.x, rects[0].center.y - rects[2].center.y;
  704. }else if(rear_abnormal_index != 3 && front_abnormal_index != 1){
  705. wb_vector << rects[1].center.x - rects[3].center.x, rects[1].center.y - rects[3].center.y;
  706. }else{
  707. return false;
  708. }
  709. wheelbase = wb_vector.norm();
  710. double alpha = 0.2;
  711. wheelbase = wheelbase + alpha * (wheelbase - 2.55);
  712. return true;
  713. }
  714. bool detect_wheel_ceres3d::get_wheel_rect(pcl::PointCloud<pcl::PointXYZ> cloud, cv::RotatedRect &rect, double &theta, double &length, double &width)
  715. {
  716. std::vector<cv::Point2f> t_point_vec;
  717. for (size_t i = 0; i < cloud.size(); i++)
  718. {
  719. t_point_vec.push_back(cv::Point2f(cloud[i].x, cloud[i].y));
  720. }
  721. if(t_point_vec.size()<=0)
  722. return false;
  723. rect = cv::minAreaRect(t_point_vec);
  724. length = std::max(rect.size.width, rect.size.height);
  725. width = std::min(rect.size.width, rect.size.height);
  726. // 车轮范围,轮胎直径600-800,宽度165-245
  727. if (length < 0.3 || length >0.9 || width < 0.1 || width > 0.3)
  728. {
  729. // std::cout << "车轮范围越界 0.3-0.9, 0.1-0.3: "<<length<<", "<<width << std::endl;
  730. return false;
  731. }
  732. // 获得真实旋转角,前轮y更大
  733. cv::Point2f corners[4];
  734. rect.points(corners);
  735. for (size_t i = 0; i < 4; i++)
  736. {
  737. for (size_t j = 0; j < 3-i; j++)
  738. {
  739. if(corners[j].y > corners[j+1].y)
  740. {
  741. std::swap(corners[j], corners[j + 1]);
  742. }
  743. }
  744. }
  745. Eigen::Vector2d rear2front;
  746. rear2front << corners[2].x + corners[3].x - corners[0].x - corners[1].x, corners[2].y + corners[3].y - corners[0].y - corners[1].y;
  747. rear2front /= 2;
  748. theta = std::atan2(rear2front.y(), rear2front.x()) * 180.0 / M_PI;
  749. return true;
  750. }
  751. bool detect_wheel_ceres3d::Solve(Detect_result &detect_result, Loss_result &loss_result, std::string &error_info)
  752. {
  753. // 20220118 added by yct. 计算比例传入模型
  754. float model_ratio = 1.0f;
  755. // bool ws_res = wheel_size_estimate(detect_result.single_wheel_width, detect_result.single_wheel_length, detect_result.theta, model_ratio);
  756. // std::cout << "change cloud with ratio: " << model_ratio << std::endl;
  757. double cx=detect_result.cx;
  758. double cy=detect_result.cy;
  759. double init_theta=detect_result.theta;
  760. double init_wheel_base=2.7;
  761. if(detect_result.wheel_base>2.55 && detect_result.wheel_base<3.2)
  762. init_wheel_base = detect_result.wheel_base;
  763. double init_width = 1.75;// detect_result.width;
  764. double init_theta_front = 0*M_PI/180.0;
  765. double variable[] = {cx, cy, init_theta, init_wheel_base, init_width, init_theta_front, 0, 0, 0, 0};
  766. // printf("init solve x:%.3f y: %.3f wheel:%.3f width:%.3f theta : %.3f front theta: %.3f\n",
  767. // variable[0], variable[1], variable[3], variable[4], variable[2], variable[5]);
  768. // 第二部分:构建寻优问题
  769. ceres::Problem problem;
  770. CostFunctor3d *cost_func = new CostFunctor3d(m_left_front_cloud,m_right_front_cloud,m_left_rear_cloud,m_right_rear_cloud,
  771. *mp_left_grid,*mp_right_grid, model_ratio);
  772. //使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个1是输入维度,即待寻优参数x的维度。
  773. ceres::CostFunction* cost_function =new
  774. ceres::AutoDiffCostFunction<CostFunctor3d, ceres::DYNAMIC, 10>(
  775. cost_func,
  776. m_left_front_cloud.size()+m_right_front_cloud.size()+m_left_rear_cloud.size()+m_right_rear_cloud.size());
  777. problem.AddResidualBlock(cost_function, NULL, variable); //向问题中添加误差项,本问题比较简单,添加一个就行。
  778. // 设置参数边界
  779. problem.SetParameterLowerBound(variable, 3, 2.00); // 最小轴距
  780. problem.SetParameterUpperBound(variable, 3, 3.50); // 最大轴距
  781. problem.SetParameterLowerBound(variable, 4, 1.0); // 最小车宽
  782. problem.SetParameterUpperBound(variable, 4, 2.5); // 最大车宽
  783. problem.SetParameterLowerBound(variable, 6, -0.1);
  784. problem.SetParameterUpperBound(variable, 6, 0.1);
  785. problem.SetParameterLowerBound(variable, 7, -0.1);
  786. problem.SetParameterUpperBound(variable, 7, 0.1);
  787. problem.SetParameterLowerBound(variable, 8, -0.1);
  788. problem.SetParameterUpperBound(variable, 8, 0.1);
  789. problem.SetParameterLowerBound(variable, 9, -0.1);
  790. problem.SetParameterUpperBound(variable, 9, 0.1);
  791. //第三部分: 配置并运行求解器
  792. ceres::Solver::Options options;
  793. // options.use_nonmonotonic_steps=false;
  794. options.linear_solver_type = ceres::DENSE_QR; //配置增量方程的解法
  795. //options.logging_type = ceres::LoggingType::SILENT;
  796. options.max_num_iterations=500;
  797. options.num_threads=2;
  798. options.minimizer_progress_to_stdout = false;//输出到cout
  799. ceres::Solver::Summary summary;//优化信息
  800. ceres::Solve(options, &problem, &summary);//求解!!!
  801. // printf("after solve x:%.3f y: %.3f wheel:%.3f width:%.3f theta : %.3f front theta: %.3f\n",
  802. // variable[0], variable[1], variable[3], variable[4], variable[2], variable[5]);
  803. double loss=summary.final_cost/(m_left_front_cloud.size()+m_right_front_cloud.size()+m_left_rear_cloud.size()+m_right_rear_cloud.size());
  804. detect_result.cx=variable[0];
  805. detect_result.cy=variable[1];
  806. detect_result.theta=(-variable[2])*180.0/M_PI;
  807. detect_result.wheel_base=variable[3];
  808. detect_result.wheel_width=variable[4];
  809. detect_result.front_theta=-(variable[5]*180.0/M_PI);
  810. if(detect_result.theta>180.0)
  811. detect_result.theta=detect_result.theta-180.0;
  812. if(detect_result.theta<0)
  813. detect_result.theta+=180.0;
  814. if(summary.iterations.size()<=1){
  815. error_info.append(std::string("仅迭代一轮,优化异常"));
  816. return false;
  817. }
  818. if(summary.iterations[summary.iterations.size()-1].iteration<=1){
  819. error_info.append(std::string("最终仅迭代一轮,优化异常"));
  820. return false;
  821. }
  822. if(detect_result.theta > 120 || detect_result.theta < 60)
  823. {
  824. error_info.append("车身角度错误 ").append(std::to_string(detect_result.theta)).append("\t");
  825. return false;
  826. }
  827. if(fabs(detect_result.front_theta)>35)
  828. {
  829. error_info.append("前轮角度错误 ").append(std::to_string(detect_result.front_theta)).append("\t");
  830. return false;
  831. }
  832. // 将loss传出
  833. if(cost_func != nullptr)
  834. {
  835. double costs_lf, costs_rf, costs_lr, costs_rr;
  836. get_costs(variable,costs_lf, costs_rf, costs_lr, costs_rr);
  837. loss_result.lf_loss = costs_lf/float(m_left_front_cloud.size()+1e-6);
  838. loss_result.rf_loss = costs_rf/float(m_right_front_cloud.size()+1e-6);
  839. loss_result.lb_loss = costs_lr/float(m_left_rear_cloud.size()+1e-6);
  840. loss_result.rb_loss = costs_rr/float(m_right_rear_cloud.size()+1e-6);
  841. loss_result.total_avg_loss = loss;
  842. detect_result.loss=loss_result;
  843. if(loss_result.lf_loss>0.4 || loss_result.rf_loss>0.4
  844. ||loss_result.lb_loss>0.4||loss_result.rb_loss>0.4)
  845. {
  846. error_info.append("loss过大 lf").append(std::to_string(loss_result.lf_loss)).append(",rf").append(std::to_string(loss_result.rf_loss)).append(", lr").
  847. append(std::to_string(loss_result.lb_loss)).append(",rb").append(std::to_string(loss_result.rb_loss));
  848. return false;
  849. }
  850. }
  851. else
  852. {
  853. return false;
  854. }
  855. return true;
  856. }