cnn3d_segmentation.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. #include "cnn3d_segmentation.h"
  2. #include "tf_wheel_3Dcnn_api.h"
  3. #include <iostream>
  4. #include <glog/logging.h>
  5. #include <pcl/segmentation/extract_clusters.h>
  6. #include <pcl/kdtree/kdtree.h>
  7. #include <pcl/sample_consensus/model_types.h>
  8. #include <pcl/filters/statistical_outlier_removal.h>
  9. #include <pcl/filters/project_inliers.h>
  10. #include <pcl/surface/convex_hull.h>
  11. #include <pcl/features/moment_of_inertia_estimation.h>
  12. #include <pcl/common/centroid.h>
  13. void save_rgb_cloud_txt(std::string txt, pcl::PointCloud<pcl::PointXYZRGB>::Ptr pCloud)
  14. {
  15. std::ofstream os;
  16. os.open(txt, std::ios::out);
  17. for (int i = 0; i < pCloud->points.size(); i++)
  18. {
  19. pcl::PointXYZRGB point = pCloud->points[i];
  20. char buf[255];
  21. memset(buf, 0, 255);
  22. sprintf(buf, "%f %f %f %d %d %d\n", point.x, point.y, point.z, point.r, point.g, point.b);
  23. os.write(buf, strlen(buf));
  24. }
  25. os.close();
  26. }
  27. double Cnn3d_segmentation::distance(cv::Point2f p1, cv::Point2f p2)
  28. {
  29. return sqrt(pow(p1.x - p2.x, 2.0) + pow(p1.y - p2.y, 2.0));
  30. }
  31. cv::RotatedRect minAreaRect_cloud(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud)
  32. {
  33. std::vector<cv::Point2f> points;
  34. for (int i = 0; i < cloud->size(); ++i)
  35. {
  36. pcl::PointXYZRGB point = cloud->points[i];
  37. points.push_back(cv::Point2f(point.x, point.y));
  38. }
  39. cv::RotatedRect rect= cv::minAreaRect(points);
  40. return rect;
  41. }
  42. cv::RotatedRect minAreaRect_cloud(std::vector<cv::Point2f> centers)
  43. {
  44. cv::RotatedRect rect = cv::minAreaRect(centers);
  45. return rect;
  46. }
  47. Error_manager Cnn3d_segmentation::set_parameter(int l, int w, int h,int freq,int classes)
  48. {
  49. m_lenth = l;
  50. m_width = w;
  51. m_height = h;
  52. m_freq = freq;
  53. m_nClass = classes;
  54. return SUCCESS;
  55. }
  56. Cnn3d_segmentation::Cnn3d_segmentation(int l, int w, int h,int freq,int classes)
  57. {
  58. m_lenth = l;
  59. m_width = w;
  60. m_height = h;
  61. m_freq = freq;
  62. m_nClass = classes;
  63. }
  64. Cnn3d_segmentation::~Cnn3d_segmentation()
  65. {
  66. //3dcnn 原校验功能保留,不加载网络
  67. //tf_wheel_3dcnn_close();
  68. }
  69. Error_manager Cnn3d_segmentation::init(std::string weights)
  70. {
  71. //3dcnn 原校验功能保留,不加载网络
  72. return SUCCESS;
  73. /*if (0 != tf_wheel_3dcnn_init(weights, m_lenth,m_width,m_height))
  74. {
  75. std::string error_description="tf_wheel_3Dcnn model load failed :";
  76. error_description+=weights;
  77. return Error_manager(LOCATER_3DCNN_INIT_FAILED,MINOR_ERROR,error_description);
  78. }
  79. //空跑一次
  80. float* data = (float*)malloc(m_lenth*m_width*m_height*sizeof(float));
  81. float* pout = (float*)malloc(m_lenth*m_width*m_height*m_nClass*sizeof(float));
  82. if (!tf_wheel_3dcnn_predict(data, pout))
  83. {
  84. free(data);
  85. free(pout);
  86. return Error_manager(LOCATER_3DCNN_PREDICT_FAILED,MINOR_ERROR,"first locate 3dcnn failed");
  87. }
  88. free(data);
  89. free(pout);
  90. return SUCCESS;*/
  91. }
  92. void save_cloudT(std::string txt, pcl::PointCloud<pcl::PointXYZRGB>& pCloud)
  93. {
  94. std::ofstream os;
  95. os.open(txt, std::ios::out);
  96. for (int i = 0; i < pCloud.points.size(); i++)
  97. {
  98. pcl::PointXYZRGB point = pCloud.points[i];
  99. char buf[255];
  100. memset(buf, 0, 255);
  101. sprintf(buf, "%f %f %f\n", point.x, point.y, point.z);
  102. os.write(buf, strlen(buf));
  103. }
  104. os.close();
  105. }
  106. Error_manager Cnn3d_segmentation::analytic_wheel(std::map<int,pcl::PointCloud<pcl::PointXYZRGB>::Ptr>& wheel_cloud_map, bool cloud_aggregation_flag,
  107. Locate_information* p_locate_information,
  108. bool save_flag, std::string save_dir)
  109. {
  110. Error_manager t_error;
  111. if ( p_locate_information == NULL )
  112. {
  113. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  114. " analytic_wheel POINTER_IS_NULL ");
  115. }
  116. //第一步 离群点过滤
  117. t_error = filter_cloud_with_outlier_for_map(wheel_cloud_map);
  118. if ( t_error != Error_code::SUCCESS)
  119. {
  120. return t_error;
  121. }
  122. //第二步, //将map分为4个轮胎
  123. //注: 前面的雷达扫描并point sift之后, 可能只能识别3个轮胎, 此时允许3个轮胎 继续运行.
  124. std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> wheel_source_vector; //拆分后的轮胎点云, 不同的轮胎点是分开的,
  125. t_error = split_wheel_cloud(wheel_cloud_map, cloud_aggregation_flag, wheel_source_vector, save_flag, save_dir);
  126. if ( t_error != Error_code::SUCCESS)
  127. {
  128. return t_error;
  129. }
  130. //第三步, pca过滤, 并计算每个轮子的中心点
  131. std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> wheel_pca_vector; //pca过滤后的点云
  132. t_error = filter_cloud_with_pca(wheel_source_vector, wheel_pca_vector, save_flag, save_dir);
  133. if ( t_error != Error_code::SUCCESS)
  134. {
  135. return t_error;
  136. }
  137. //第四步,提取关键矩形,
  138. cv::RotatedRect rect_of_wheel_center; //4个轮胎中心点构成的矩形
  139. cv::RotatedRect rect_of_wheel_cloud; //所有点云构成的矩形
  140. t_error = extract_key_rect(wheel_pca_vector, rect_of_wheel_center, rect_of_wheel_cloud, save_flag, save_dir);
  141. if ( t_error != Error_code::SUCCESS)
  142. {
  143. return t_error;
  144. }
  145. //第五步, //通过关键矩形, 计算出车辆的定位信息, (输出中心点的x和y, 前后轮距, 左右轮距, 旋转角)
  146. t_error = calculate_key_rect(rect_of_wheel_center, rect_of_wheel_cloud, p_locate_information);
  147. if ( t_error != Error_code::SUCCESS)
  148. {
  149. return t_error;
  150. }
  151. return Error_code::SUCCESS;
  152. }
  153. //过滤离群点,
  154. Error_manager Cnn3d_segmentation::filter_cloud_with_outlier_for_map(std::map<int,pcl::PointCloud<pcl::PointXYZRGB>::Ptr>& wheel_cloud_map)
  155. {
  156. Error_manager t_error;
  157. Error_manager t_result;
  158. //遍历map, 对点云进行 离群点过滤
  159. for (auto iter = wheel_cloud_map.begin(); iter != wheel_cloud_map.end(); ++iter)
  160. {
  161. //过滤离群点,
  162. t_error = filter_cloud_with_outlier(iter->second);
  163. if (t_error != Error_code::SUCCESS)
  164. {
  165. char buf[256] = {0};
  166. sprintf(buf, " map.id = %d, filter_cloud_with_outlier error", iter->first );
  167. t_error.add_error_description(buf, strlen(buf) );
  168. t_result.compare_and_cover_error(t_error);
  169. //注:这里不直接return,而是要把map全部执行完成
  170. }
  171. }
  172. if ( t_result != Error_code::SUCCESS)
  173. {
  174. return t_result;
  175. }
  176. return Error_code::SUCCESS;
  177. }
  178. //过滤离群点,
  179. Error_manager Cnn3d_segmentation::filter_cloud_with_outlier(pcl::PointCloud<pcl::PointXYZRGB>::Ptr p_cloud)
  180. {
  181. if(p_cloud.get()==NULL)
  182. {
  183. return Error_manager(LOCATER_3DCNN_INPUT_CLOUD_UNINIT,MINOR_ERROR,"Cnn3d_segmentation input cloud uninit");
  184. }
  185. if(p_cloud->size()<=0)
  186. {
  187. return Error_manager(LOCATER_3DCNN_INPUT_CLOUD_EMPTY,MINOR_ERROR,"Cnn3d_segmentation input cloud empty");
  188. }
  189. pcl::StatisticalOutlierRemoval<pcl::PointXYZRGB> sorfilter(true); // Initializing with true will allow us to extract the removed indices
  190. sorfilter.setInputCloud(p_cloud);
  191. sorfilter.setMeanK(20);
  192. sorfilter.setStddevMulThresh(2.0);
  193. sorfilter.filter(*p_cloud);
  194. return Error_code::SUCCESS;
  195. }
  196. //拆分车轮, 将map分为4个轮胎
  197. //wheel_cloud_map, 输入点云
  198. //cloud_out_vector, 输出4轮点云vector, (vector是空的, 函数内部会添加4个点云)
  199. Error_manager Cnn3d_segmentation::split_wheel_cloud(std::map<int,pcl::PointCloud<pcl::PointXYZRGB>::Ptr>& wheel_cloud_map, bool cloud_aggregation_flag,
  200. std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & wheel_cloud_vector,
  201. bool save_flag, std::string save_dir)
  202. {
  203. Error_manager t_error;
  204. wheel_cloud_vector.clear();
  205. //如果输入的map只有一个cloud, 那么就要进行聚类, 拆分为4个轮胎
  206. if ( wheel_cloud_map.size() == 1 && cloud_aggregation_flag == true )
  207. {
  208. t_error = split_cloud_with_kmeans(wheel_cloud_map[0], wheel_cloud_vector, save_flag, save_dir);
  209. //注:此时wheel_clouds_vector里面可能有一个的点云为空的,
  210. if ( t_error != Error_code::SUCCESS )
  211. {
  212. return t_error;
  213. }
  214. }
  215. //如果输入的map有3~4个cloud, 那么就直接复制,
  216. else if ( (wheel_cloud_map.size() == CNN3D_WHEEL_NUMBER || wheel_cloud_map.size() == CNN3D_WHEEL_NUMBER - 1 )
  217. && cloud_aggregation_flag == false )
  218. {
  219. for (auto iter = wheel_cloud_map.begin(); iter != wheel_cloud_map.end(); ++iter)
  220. {
  221. wheel_cloud_vector.push_back(iter->second);
  222. //注:此时的 clouds_vector 可能有3~4个点云,
  223. }
  224. }
  225. else
  226. {
  227. return Error_manager(Error_code::LOCATER_3DCNN_INPUT_CLOUD_MAP_ERROR, Error_level::MINOR_ERROR,
  228. " split_wheel_cloud p_wheel_cloud_map size error ");
  229. }
  230. return Error_code::SUCCESS;
  231. }
  232. //聚类, 将一个车轮点云拆分为4个轮胎点云,
  233. //p_cloud_in, 输入点云
  234. //cloud_out_vector, 输出4轮点云vector, (vector是空的, 函数内部会添加4个点云)
  235. Error_manager Cnn3d_segmentation::split_cloud_with_kmeans(pcl::PointCloud<pcl::PointXYZRGB>::Ptr p_cloud_in,
  236. std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & cloud_out_vector,
  237. bool save_flag, std::string save_dir)
  238. {
  239. if(p_cloud_in.get()==NULL)
  240. {
  241. return Error_manager(LOCATER_3DCNN_INPUT_CLOUD_UNINIT,MINOR_ERROR,"Cnn3d_segmentation input cloud uninit");
  242. }
  243. if(p_cloud_in->size()<=0)
  244. {
  245. return Error_manager(LOCATER_3DCNN_INPUT_CLOUD_EMPTY,MINOR_ERROR,"Cnn3d_segmentation input cloud empty");
  246. }
  247. //为cloud_out_vector重新分配内存, 添加4个轮胎点云
  248. cloud_out_vector.clear();
  249. for(int i=0;i<CNN3D_WHEEL_NUMBER;++i)
  250. {
  251. pcl::PointCloud<pcl::PointXYZRGB>::Ptr t_cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
  252. cloud_out_vector.push_back(t_cloud);
  253. }
  254. //开始分割,
  255. //注: 实际上只考虑了x和y轴, 以水平面为标准,
  256. // 根据每个点到的4个角落的距离, 分为4个车轮
  257. //p_cloud_in转化为opencv的点云
  258. std::vector<cv::Point2f> cv_points;
  259. for (int i = 0; i < p_cloud_in->size(); ++i)
  260. {
  261. cv::Point2f point(p_cloud_in->points[i].x, p_cloud_in->points[i].y);
  262. cv_points.push_back(point);
  263. }
  264. //rect 为输入点云的外截最小矩形
  265. cv::RotatedRect rect = cv::minAreaRect(cv_points);
  266. //corner 为矩形的4个角落的点
  267. cv::Point2f corner[CNN3D_WHEEL_NUMBER];
  268. rect.points(corner);
  269. //遍历输入点云
  270. for (int i = 0; i < p_cloud_in->size(); ++i)
  271. {
  272. //计算出当前点距离哪个角落最近,
  273. double min_distance = 9999999.9; //当前点距离角落的最小距离
  274. int cluste_index = 0; //当前点最近角落的索引编号
  275. cv::Point2f point(p_cloud_in->points[i].x, p_cloud_in->points[i].y);
  276. for (int j = 0; j < CNN3D_WHEEL_NUMBER; ++j)
  277. {
  278. double dis=distance(point, corner[j]);
  279. if (dis < min_distance)
  280. {
  281. min_distance = dis;
  282. cluste_index = j;
  283. }
  284. }
  285. //根据点位的归属, 将其重新标色并填充到对应的输出点云
  286. if (cluste_index == 0)
  287. {
  288. p_cloud_in->points[i].r = 255;
  289. p_cloud_in->points[i].g = 0;
  290. p_cloud_in->points[i].b = 0;
  291. }
  292. else if (cluste_index == 1)
  293. {
  294. p_cloud_in->points[i].r = 0;
  295. p_cloud_in->points[i].g = 255;
  296. p_cloud_in->points[i].b = 0;
  297. }
  298. else if (cluste_index == 2)
  299. {
  300. p_cloud_in->points[i].r = 0;
  301. p_cloud_in->points[i].g = 0;
  302. p_cloud_in->points[i].b = 255;
  303. }
  304. else
  305. {
  306. p_cloud_in->points[i].r = 255;
  307. p_cloud_in->points[i].g = 255;
  308. p_cloud_in->points[i].b = 255;
  309. }
  310. cloud_out_vector[cluste_index]->push_back(p_cloud_in->points[i]);
  311. }
  312. //保存修改颜色后的点云.
  313. if ( save_flag )
  314. {
  315. std::string save_file=save_dir+"/cnn3d_with_kmeans.txt";
  316. save_rgb_cloud_txt(save_file, p_cloud_in);
  317. }
  318. return Error_code::SUCCESS;
  319. }
  320. //pca, 使用pca算法对每个车轮的点云进行过滤,
  321. Error_manager Cnn3d_segmentation::filter_cloud_with_pca(std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & cloud_in_vector,
  322. std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & cloud_out_vector,
  323. bool save_flag, std::string save_dir)
  324. {
  325. Error_manager t_error;
  326. cloud_out_vector.clear();
  327. for (int i = 0; i < cloud_in_vector.size(); ++i)
  328. {
  329. if ( cloud_in_vector[i]->size() != 0 )
  330. {
  331. pcl::PointCloud<pcl::PointXYZRGB>::Ptr tp_cloud_pca(new pcl::PointCloud<pcl::PointXYZRGB>);
  332. //对点云作pca分析,然后在最小轴方向过滤, 防止轮胎左右两边出现噪声
  333. t_error = pca_minist_axis_filter(cloud_in_vector[i],tp_cloud_pca);
  334. if ( t_error != Error_code::SUCCESS )
  335. {
  336. return t_error;
  337. }
  338. cloud_out_vector.push_back(tp_cloud_pca);
  339. if ( save_flag )
  340. {
  341. char buf[255]={0};
  342. sprintf(buf,"%s/cnn3d_pca_wheel_%d.txt",save_dir.c_str(),i);
  343. save_cloudT(buf,*tp_cloud_pca);
  344. }
  345. }
  346. }
  347. //验证 vector 的大小
  348. if ( cloud_out_vector.size() < CNN3D_WHEEL_NUMBER - 1)
  349. {
  350. return Error_manager(Error_code::LOCATER_3DCNN_PCA_OUT_ERROR, Error_level::MINOR_ERROR,
  351. " wheel_pca_vector.size() < 3 ");
  352. }
  353. return Error_code::SUCCESS;
  354. }
  355. //对点云作pca分析,然后在最小轴方向过滤, 防止轮胎左右两边出现噪声
  356. Error_manager Cnn3d_segmentation::pca_minist_axis_filter(pcl::PointCloud<pcl::PointXYZRGB>::Ptr p_cloud_in,
  357. pcl::PointCloud<pcl::PointXYZRGB>::Ptr p_cloud_out)
  358. {
  359. if(p_cloud_in.get()==NULL)
  360. {
  361. return Error_manager(LOCATER_3DCNN_INPUT_CLOUD_UNINIT,MINOR_ERROR,"Cnn3d_segmentation input cloud uninit");
  362. }
  363. if(p_cloud_in->size()<=0)
  364. {
  365. return Error_manager(LOCATER_3DCNN_INPUT_CLOUD_EMPTY,MINOR_ERROR,"Cnn3d_segmentation input cloud empty");
  366. }
  367. //pca寻找主轴
  368. pcl::MomentOfInertiaEstimation <pcl::PointXYZRGB> feature_extractor;
  369. feature_extractor.setInputCloud (p_cloud_in);
  370. feature_extractor.compute ();
  371. std::vector <float> moment_of_inertia;
  372. std::vector <float> eccentricity;
  373. pcl::PointXYZRGB min_point_AABB;
  374. pcl::PointXYZRGB max_point_AABB;
  375. pcl::PointXYZRGB min_point_OBB;
  376. pcl::PointXYZRGB max_point_OBB;
  377. pcl::PointXYZRGB position_OBB;
  378. Eigen::Matrix3f rotational_matrix_OBB;
  379. float major_value, middle_value, minor_value;
  380. Eigen::Vector3f major_vector, middle_vector, minor_vector;
  381. Eigen::Vector3f mass_center;
  382. feature_extractor.getMomentOfInertia (moment_of_inertia);
  383. feature_extractor.getEccentricity (eccentricity);
  384. feature_extractor.getAABB (min_point_AABB, max_point_AABB);
  385. feature_extractor.getOBB (min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);
  386. feature_extractor.getEigenValues (major_value, middle_value, minor_value);
  387. feature_extractor.getEigenVectors (major_vector, middle_vector, minor_vector);
  388. feature_extractor.getMassCenter (mass_center);
  389. //根据minor_vector 最小主轴方向,以及中心点, 计算轴所在三维平面
  390. float x=mass_center[0];
  391. float y=mass_center[1];
  392. float z=mass_center[2];
  393. float a=minor_vector[0];
  394. float b=minor_vector[1];
  395. float c=minor_vector[2];
  396. float d=-(a*x+b*y+c*z);
  397. //计算各点距离平面的距离,距离操过轮胎的一半厚,舍弃(100mm)
  398. float S=sqrt(a*a+b*b+c*c);
  399. for(int i=0;i<p_cloud_in->size();++i)
  400. {
  401. pcl::PointXYZRGB point=p_cloud_in->points[i];
  402. if(fabs(point.x*a+point.y*b+point.z*c+d)/S <40 )
  403. {
  404. p_cloud_out->push_back(point);
  405. }
  406. }
  407. /*if(cloud_out->size()==0)
  408. {
  409. return Error_manager(LOCATER_3DCNN_PCA_OUT_CLOUD_EMPTY,MINOR_ERROR,"wheel pca filter out cloud empty");
  410. }*/
  411. return SUCCESS;
  412. }
  413. //提取关键矩形,
  414. //cloud_in_vector, 输入点云
  415. //rect_of_wheel_center, 输出4轮中心点构成的矩形
  416. //rect_of_wheel_cloud, 输出所有车轮点构成的矩形
  417. Error_manager Cnn3d_segmentation::extract_key_rect(std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & cloud_in_vector,
  418. cv::RotatedRect & rect_of_wheel_center, cv::RotatedRect & rect_of_wheel_cloud,
  419. bool save_flag, std::string save_dir)
  420. {
  421. //验证 vector 的大小
  422. if ( cloud_in_vector.size() < CNN3D_WHEEL_NUMBER - 1)
  423. {
  424. return Error_manager(Error_code::LOCATER_3DCNN_EXTRACT_RECT_ERROR, Error_level::MINOR_ERROR,
  425. " cloud_in_vector.size() < 3 ");
  426. }
  427. Error_manager t_error;
  428. //4个轮子的中心点, 只要x和y轴的坐标,
  429. std::vector<cv::Point2f> wheel_center_vector;
  430. //取出轮胎的中心点
  431. for (int i = 0; i < cloud_in_vector.size(); ++i)
  432. {
  433. if ( cloud_in_vector[i]->size() != 0 )
  434. {
  435. //提取每个车轮中心点
  436. Eigen::Vector4f centroid;
  437. pcl::compute3DCentroid(*(cloud_in_vector[i]), centroid);
  438. wheel_center_vector.push_back(cv::Point2f(centroid[0],centroid[1]));
  439. }
  440. }
  441. //验证 vector 的大小
  442. int t_vector_size = wheel_center_vector.size();
  443. if ( wheel_center_vector.size() < CNN3D_WHEEL_NUMBER - 1)
  444. {
  445. return Error_manager(Error_code::LOCATER_3DCNN_EXTRACT_RECT_ERROR, Error_level::MINOR_ERROR,
  446. " wheel_center_vector.size() < 3 ");
  447. }
  448. //检查并修复关键点, 此时可以通过3个轮胎模拟出第四个轮胎的中心点位置, 并添加到 vector
  449. // t_error = check_and_repair_center(wheel_center_vector);
  450. if ( t_error != Error_code::SUCCESS )
  451. {
  452. return t_error;
  453. }
  454. //rect_of_wheel_center, 输出4轮中心点构成的矩形
  455. rect_of_wheel_center = minAreaRect_cloud(wheel_center_vector);
  456. // t_error = check_rect_size(rect_of_wheel_center);
  457. if ( t_error != Error_code::SUCCESS )
  458. {
  459. return t_error;
  460. }
  461. //将输入的车轮点云, 汇总为 cv::Point2f的vector
  462. std::vector<cv::Point2f> wheel_points_vector;
  463. for(int i=0;i<cloud_in_vector.size();++i)
  464. {
  465. for(int j=0;j<cloud_in_vector[i]->size();++j)
  466. wheel_points_vector.push_back(cv::Point2f(cloud_in_vector[i]->points[j].x,
  467. cloud_in_vector[i]->points[j].y));
  468. }
  469. //如果前面check_and_repair_center为wheel_center_vector添加了第四个中心点, 那么也要加入到wheel_points_vector
  470. if(t_vector_size == CNN3D_WHEEL_NUMBER - 1 && wheel_center_vector.size() == CNN3D_WHEEL_NUMBER)
  471. {
  472. wheel_points_vector.push_back(wheel_center_vector[CNN3D_WHEEL_NUMBER - 1]);
  473. }
  474. //rect_of_wheel_cloud, 输出所有车轮点构成的矩形
  475. rect_of_wheel_cloud = minAreaRect_cloud(wheel_points_vector);
  476. return Error_code::SUCCESS;
  477. }
  478. //检查并修复关键点, 此时可以通过3个轮胎模拟出第四个轮胎的中心点位置, 并添加到 vector
  479. Error_manager Cnn3d_segmentation::check_and_repair_center(std::vector<cv::Point2f> & cloud_centers)
  480. {
  481. //取四轮中心计算轴长
  482. return centers_is_rect(cloud_centers);
  483. }
  484. //判断矩形框是否找到
  485. //points:输入轮子中心点, 只能是3或者4个
  486. Error_manager Cnn3d_segmentation::centers_is_rect(std::vector<cv::Point2f>& points)
  487. {
  488. if (points.size() == 4)
  489. {
  490. double L[3] = {0.0};
  491. L[0] = distance(points[0], points[1]);
  492. L[1] = distance(points[1], points[2]);
  493. L[2] = distance(points[0], points[2]);
  494. double max_l = L[0];
  495. double l1 = L[1];
  496. double l2 = L[2];
  497. int max_index = 0;
  498. cv::Point2f ps = points[0], pt = points[1];
  499. cv::Point2f pc = points[2];
  500. for (int i = 1; i < 3; ++i) {
  501. if (L[i] > max_l) {
  502. max_index = i;
  503. max_l = L[i];
  504. l1 = L[abs(i + 1) % 3];
  505. l2 = L[abs(i + 2) % 3];
  506. ps = points[i % 3];
  507. pt = points[(i + 1) % 3];
  508. pc = points[(i + 2) % 3];
  509. }
  510. }
  511. double cosa = (l1 * l1 + l2 * l2 - max_l * max_l) / (2.0 * l1 * l2);
  512. if (fabs(cosa) >= 0.13) {
  513. char description[255]={0};
  514. sprintf(description,"angle cos value(%.2f) >0.13 ",cosa);
  515. return Error_manager(LOCATER_3DCNN_VERIFY_RECT_FAILED_4,MINOR_ERROR,description);
  516. }
  517. float width=std::min(l1,l2);
  518. float length=std::max(l1,l2);
  519. if(width<1400 || width >2000 || length >3300 ||length < 2200)
  520. {
  521. char description[255]={0};
  522. sprintf(description,"width<1400 || width >2100 || length >3300 ||length < 2100 l:%.1f,w:%.1f",length,width);
  523. return Error_manager(LOCATER_3DCNN_VERIFY_RECT_FAILED_4,MINOR_ERROR,description);
  524. }
  525. double d = distance(pc, points[3]);
  526. cv::Point2f center1 = (ps + pt) * 0.5;
  527. cv::Point2f center2 = (pc + points[3]) * 0.5;
  528. if (fabs(d - max_l) > max_l * 0.1 || distance(center1, center2) > 150) {
  529. LOG(INFO) << "d:" << d << " maxl:" << max_l << " center1:" << center1 << " center2:" << center2;
  530. char description[255]={0};
  531. sprintf(description,"Verify failed-4 fabs(d - max_l) > max_l * 0.1 || distance(center1, center2) > 150 ");
  532. return Error_manager(LOCATER_3DCNN_VERIFY_RECT_FAILED_4,MINOR_ERROR,description);
  533. }
  534. LOG(INFO) << " rectangle verify OK cos angle=" << cosa << " length off=" << fabs(d - max_l)
  535. << " center distance=" << distance(center1, center2);
  536. return SUCCESS;
  537. }
  538. else if(points.size()==3)
  539. {
  540. double L[3] = {0.0};
  541. L[0] = distance(points[0], points[1]);
  542. L[1] = distance(points[1], points[2]);
  543. L[2] = distance(points[0], points[2]);
  544. double max_l = L[0];
  545. double l1 = L[1];
  546. double l2 = L[2];
  547. int max_index = 0;
  548. cv::Point2f ps = points[0], pt = points[1];
  549. cv::Point2f pc = points[2];
  550. for (int i = 1; i < 3; ++i) {
  551. if (L[i] > max_l) {
  552. max_index = i;
  553. max_l = L[i];
  554. l1 = L[abs(i + 1) % 3];
  555. l2 = L[abs(i + 2) % 3];
  556. ps = points[i % 3];
  557. pt = points[(i + 1) % 3];
  558. pc = points[(i + 2) % 3];
  559. }
  560. }
  561. double cosa = (l1 * l1 + l2 * l2 - max_l * max_l) / (2.0 * l1 * l2);
  562. if (fabs(cosa) >= 0.12) {
  563. char description[255]={0};
  564. sprintf(description,"3 wheels angle cos value(%.2f) >0.12 ",cosa);
  565. return Error_manager(LOCATER_3DCNN_VERIFY_RECT_FAILED_3,MINOR_ERROR,description);
  566. }
  567. double l=std::max(l1,l2);
  568. double w=std::min(l1,l2);
  569. if(l>2100 && l<3300 && w>1400 && w<2100)
  570. {
  571. //生成第四个点
  572. cv::Point2f vec1=ps-pc;
  573. cv::Point2f vec2=pt-pc;
  574. cv::Point2f point4=(vec1+vec2)+pc;
  575. points.push_back(point4);
  576. LOG(INFO) << "3 wheels rectangle verify OK cos angle=" << cosa << " L=" << l
  577. << " w=" << w;
  578. return SUCCESS;
  579. }
  580. else
  581. {
  582. char description[255]={0};
  583. sprintf(description,"3 wheels rectangle verify Failed cos angle=%.2f,L=%.1f, w=%.1f",cosa,l,w);
  584. return Error_manager(LOCATER_3DCNN_VERIFY_RECT_FAILED_3,MINOR_ERROR,description);
  585. }
  586. }
  587. return Error_code::SUCCESS;
  588. }
  589. //检查矩形的大小
  590. Error_manager Cnn3d_segmentation::check_rect_size(cv::RotatedRect& rect)
  591. {
  592. if ( std::min(rect.size.width, rect.size.height)>2.000 || std::min(rect.size.width, rect.size.height)<1.200)
  593. {
  594. return Error_manager(Error_code::LOCATER_3DCNN_RECT_SIZE_ERROR, Error_level::MINOR_ERROR,
  595. " check_rect_size error ");
  596. }
  597. if (std::max(rect.size.width, rect.size.height) < 1.900 || std::max(rect.size.width, rect.size.height) > 3.600)
  598. {
  599. return Error_manager(Error_code::LOCATER_3DCNN_RECT_SIZE_ERROR, Error_level::MINOR_ERROR,
  600. " check_rect_size error ");
  601. }
  602. return Error_code::SUCCESS;
  603. }
  604. //通过关键矩形, 计算出车辆的定位信息, (输出中心点的x和y, 前后轮距, 左右轮距, 旋转角)
  605. Error_manager Cnn3d_segmentation::calculate_key_rect(cv::RotatedRect & rect_of_wheel_center, cv::RotatedRect & rect_of_wheel_cloud,
  606. Locate_information* p_locate_information)
  607. {
  608. if ( p_locate_information == NULL )
  609. {
  610. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  611. " calculate_key_rect input parameter POINTER_IS_NULL ");
  612. }
  613. //计算中心点
  614. p_locate_information->locate_x=rect_of_wheel_center.center.x;
  615. p_locate_information->locate_y=rect_of_wheel_center.center.y;
  616. //计算轮距, 矩形的长边为前后轮距, 短边为左右轮距
  617. p_locate_information->locate_wheel_base=std::max(rect_of_wheel_center.size.height,rect_of_wheel_center.size.width);
  618. p_locate_information->locate_wheel_width=std::min(rect_of_wheel_center.size.height,rect_of_wheel_center.size.width);
  619. //计算旋转角
  620. const double C_PI=3.14159265;
  621. cv::Point2f vec;
  622. cv::Point2f vertice[4];
  623. rect_of_wheel_cloud.points(vertice);
  624. float len1 = pow(vertice[0].x - vertice[1].x, 2.0) + pow(vertice[0].y - vertice[1].y, 2.0);
  625. float len2 = pow(vertice[1].x - vertice[2].x, 2.0) + pow(vertice[1].y - vertice[2].y, 2.0);
  626. if (len1 > len2) {
  627. vec.x = vertice[0].x - vertice[1].x;
  628. vec.y = vertice[0].y - vertice[1].y;
  629. }
  630. else
  631. {
  632. vec.x = vertice[1].x - vertice[2].x;
  633. vec.y = vertice[1].y - vertice[2].y;
  634. }
  635. p_locate_information->locate_angle = 180.0 / C_PI * acos(vec.x / sqrt(vec.x * vec.x + vec.y * vec.y));
  636. LOG(INFO)<<"3dcnn rotate rect center :"<<rect_of_wheel_center.center<<" size : "<<rect_of_wheel_center.size<<" angle:"<<p_locate_information->locate_angle;
  637. return SUCCESS;
  638. }