locater.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. //
  2. // Created by zx on 2019/12/30.
  3. //
  4. #include "locater.h"
  5. #include <pcl/filters//voxel_grid.h>
  6. #include <pcl/filters/passthrough.h>
  7. #include <glog/logging.h>
  8. Locater::Locater():mp_yolo_detector(0),mp_point_sift(0),mp_cnn3d(0)
  9. {
  10. }
  11. Locater::~Locater()
  12. {}
  13. Error_manager Locater::get_error()
  14. {
  15. return SUCCESS;
  16. }
  17. Error_manager Locater::init(Measure::LocateParameter parameter)
  18. {
  19. Error_manager code;
  20. {
  21. int point_size = parameter.seg_parameter().point_size();
  22. int cls_num = parameter.seg_parameter().cls_num();
  23. double freq = parameter.seg_parameter().freq();
  24. std::string graph = parameter.seg_parameter().graph();
  25. std::string cpkt = parameter.seg_parameter().cpkt();
  26. Measure::Area3d area = parameter.seg_parameter().area();
  27. pcl::PointXYZ minp(area.x_min(), area.y_min(), area.z_min());
  28. pcl::PointXYZ maxp(area.x_max(), area.y_max(), area.z_max());
  29. LOG(INFO)<<"Creating pointSift net ...";
  30. mp_point_sift = new Point_sift_segmentation(point_size,cls_num,freq,minp,maxp);
  31. std::string graph_file = graph;
  32. std::string cpkt_file = cpkt;
  33. LOG(INFO)<<"init pointSift net graph:"<<graph;
  34. code=mp_point_sift->init(graph_file,cpkt_file);
  35. if(code!=SUCCESS)
  36. {
  37. LOG(ERROR)<<code.to_string();
  38. return code;
  39. }
  40. }
  41. {
  42. LOG(INFO)<<"Creating darknet ...";
  43. float min_x = parameter.yolo_parameter().min_x();
  44. float max_x = parameter.yolo_parameter().max_x();
  45. float min_y = parameter.yolo_parameter().min_y();
  46. float max_y = parameter.yolo_parameter().max_y();
  47. float freq = parameter.yolo_parameter().freq();
  48. std::string cfg = parameter.yolo_parameter().cfg();
  49. std::string weights = parameter.yolo_parameter().weights();
  50. mp_yolo_detector = new YoloDetector(cfg, weights, min_x, max_x, min_y, max_y, freq);
  51. }
  52. int l = parameter.net_3dcnn_parameter().length();
  53. int w = parameter.net_3dcnn_parameter().width();
  54. int h = parameter.net_3dcnn_parameter().height();
  55. int nClass = parameter.net_3dcnn_parameter().nclass();
  56. int freq = parameter.net_3dcnn_parameter().freq();
  57. mp_cnn3d = new Cnn3d_segmentation(l, w, h, freq, nClass);
  58. LOG(INFO)<<"Init 3dcnn ...";
  59. std::string weights = parameter.net_3dcnn_parameter().weights_file();
  60. code=mp_cnn3d->init(weights);
  61. if(code!=SUCCESS)
  62. {
  63. return code;
  64. }
  65. return SUCCESS;
  66. }
  67. Error_manager Locater::execute_task(Task_Base* task,double time_out)
  68. {
  69. LOG(INFO)<<"NEW LOCATE TASK ==============================================================================";
  70. Locate_information locate_information;
  71. locate_information.locate_correct=false;
  72. //判断task是否合法
  73. if(task==0) return LOCATER_TASK_ERROR;
  74. if(task->get_task_type()!=LOCATE_TASK)
  75. {
  76. task->update_statu(TASK_OVER,"locate task type error");
  77. return Error_manager(LOCATER_TASK_ERROR,NORMAL,"locate Task type error");
  78. }
  79. Locate_task* locate_task=(Locate_task*)task;
  80. locate_task->update_statu(TASK_SIGNED);
  81. Error_manager code;
  82. ///第一步,获取task中input点云,文件保存路径
  83. pcl::PointCloud<pcl::PointXYZ>::Ptr t_cloud_input=locate_task->get_locate_cloud();
  84. std::string save_path=locate_task->get_save_path();
  85. if(t_cloud_input.get()==0)
  86. {
  87. locate_task->update_statu(TASK_OVER,"Task set cloud is uninit");
  88. return Error_manager(LOCATER_INPUT_CLOUD_UNINIT,NORMAL,"Task set cloud is uninit");
  89. }
  90. //第二步,加锁,更新task状态,调用locate,进入测量中
  91. std::lock_guard<std::mutex> t_lock(m_mutex_lock);
  92. locate_task->update_statu(TASK_WORKING);
  93. code=locate(t_cloud_input,locate_information,save_path);
  94. locate_task->set_locate_cloud(t_cloud_input);
  95. locate_task->set_locate_information(locate_information);
  96. if(code!=SUCCESS)
  97. {
  98. locate_task->update_statu(TASK_OVER,"Locate Failed");
  99. return code;
  100. }
  101. locate_task->update_statu(TASK_OVER,"Locate OK");
  102. return code;
  103. }
  104. Error_manager Locater::locate_yolo(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in,
  105. std::vector<YoloBox>& boxes, std::string work_dir)
  106. {
  107. if(cloud_in.get()==0)
  108. {
  109. return Error_manager(LOCATER_YOLO_INPUT_CLOUD_UNINIT,NORMAL,"yolo input cloud uninit");
  110. }
  111. if(cloud_in->size()==0)
  112. {
  113. return Error_manager(LOCATER_INPUT_YOLO_CLOUD_EMPTY,NORMAL,"locate_yolo input cloud empty");
  114. }
  115. if(mp_yolo_detector==0)
  116. {
  117. return Error_manager(LOCATER_YOLO_UNINIT,NORMAL,"locate_yolo yolo is not init");
  118. }
  119. //1,根据点云区域,调整yolo边界参数,边界参数必须保证长宽 1:1
  120. pcl::PointXYZ min_point,max_point;
  121. pcl::getMinMax3D(*cloud_in,min_point,max_point);
  122. float yolo_minx=min_point.x;
  123. float yolo_maxx=max_point.x;
  124. float yolo_miny=min_point.y;
  125. float yolo_maxy=max_point.y;
  126. float length=yolo_maxx-yolo_minx;
  127. float width=yolo_maxy-yolo_miny;
  128. if(length>2*width) yolo_maxy=(length/2.0)+yolo_miny;
  129. else if(length<2*width) yolo_maxx=(2*width)+yolo_minx;
  130. Error_manager code=mp_yolo_detector->set_region(yolo_minx,yolo_maxx,yolo_miny,
  131. yolo_maxy,m_locate_parameter.yolo_parameter().freq());
  132. if(code!=SUCCESS)
  133. {
  134. return code;
  135. }
  136. //2,识别车辆位置
  137. boxes.clear();
  138. return mp_yolo_detector->detect(cloud_in,boxes,work_dir);
  139. }
  140. Error_manager Locater::locate_sift(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in, std::vector<YoloBox> boxes,
  141. pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_wheel,pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_car,
  142. std::string work_dir)
  143. {
  144. if(cloud_in.get()==0)
  145. {
  146. return Error_manager(LOCATER_SIFT_INPUT_CLOUD_UNINIT,NORMAL,"sift input cloud uninit");
  147. }
  148. if(cloud_in->size()==0)
  149. {
  150. return Error_manager(LOCATER_SIFT_INPUT_CLOUD_EMPTY,NORMAL,"locate_sift input cloud empty");
  151. }
  152. if(mp_point_sift==0)
  153. {
  154. return Error_manager(LOCATER_POINTSIFT_UNINIT,NORMAL,"Point Sift unInit");
  155. }
  156. //第一步,根据点云边界调整PointSIft 参数
  157. pcl::PointXYZ min_point,max_point;
  158. pcl::getMinMax3D(*cloud_in,min_point,max_point);
  159. Error_manager code ;
  160. code=mp_point_sift->set_region(min_point,max_point);
  161. if(code!=SUCCESS)
  162. {
  163. return code;
  164. }
  165. //第二步,点云抽稀,抽稀后的点云大约在8192左右,
  166. // 如果有多辆车(多个yolo框),取第一个框
  167. YoloBox yolo_box=boxes[0];
  168. pcl::PointXYZ minp, maxp;
  169. minp.x = yolo_box.x;
  170. minp.y = yolo_box.y;
  171. maxp.x = minp.x + yolo_box.w;
  172. maxp.y = minp.y + yolo_box.h;
  173. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_input_sift(new pcl::PointCloud<pcl::PointXYZ>());
  174. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_downsample(new pcl::PointCloud<pcl::PointXYZ>());
  175. /// ///体素网格 下采样
  176. pcl::VoxelGrid<pcl::PointXYZ> vgfilter;
  177. vgfilter.setInputCloud(cloud_in);
  178. vgfilter.setLeafSize(60.f, 60.f, 50.f);
  179. vgfilter.filter(*cloud_downsample);
  180. //限制 x y
  181. pcl::PassThrough<pcl::PointXYZ> passX;
  182. pcl::PassThrough<pcl::PointXYZ> passY;
  183. pcl::PassThrough<pcl::PointXYZ> passZ;
  184. passX.setInputCloud(cloud_downsample);
  185. passX.setFilterFieldName("x");
  186. passX.setFilterLimits(minp.x, maxp.x);
  187. passX.filter(*cloud_in);
  188. passY.setInputCloud(cloud_in);
  189. passY.setFilterFieldName("y");
  190. passY.setFilterLimits(minp.y, maxp.y);
  191. passY.filter(*cloud_in);
  192. passY.setInputCloud(cloud_in);
  193. passY.setFilterFieldName("z");
  194. passY.setFilterLimits(40, 2000);
  195. passY.filter(*cloud_in);
  196. //第三步,分割车辆点云
  197. std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> segmentation_clouds;
  198. code=mp_point_sift->seg(cloud_in, segmentation_clouds, work_dir);
  199. if(code!=SUCCESS)
  200. {
  201. return code;
  202. }
  203. if(segmentation_clouds[0]->size()==0||segmentation_clouds[2]->size()==0)
  204. {
  205. return Error_manager(LOCATER_SIFT_PREDICT_NO_CAR_POINT,NORMAL,"sift predict no car or wheel");
  206. }
  207. pcl::PointCloud<pcl::PointXYZ>::Ptr t_cloud_car(new pcl::PointCloud<pcl::PointXYZ>);
  208. pcl::PointCloud<pcl::PointXYZ>::Ptr t_cloud_wheel(new pcl::PointCloud<pcl::PointXYZ>);
  209. //第0类即是轮胎点云,第二类为车身点云
  210. pcl::copyPointCloud(*segmentation_clouds[0], *t_cloud_wheel);
  211. pcl::copyPointCloud(*segmentation_clouds[2], *t_cloud_car);
  212. cloud_wheel=t_cloud_wheel;
  213. cloud_car=t_cloud_car;
  214. return SUCCESS;
  215. }
  216. Error_manager Locater::locate_wheel(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
  217. float& center_x,float& center_y,
  218. float& wheel_base,float& width,float& angle,
  219. std::string work_dir)
  220. {
  221. if(cloud.get()==0)
  222. {
  223. return Error_manager(LOCATER_3DCNN_INPUT_CLOUD_UNINIT,NORMAL,"3dcnn input cloud uninit");
  224. }
  225. if(cloud->size()==0)
  226. {
  227. return Error_manager(LOCATER_3DCNN_INPUT_CLOUD_EMPTY,NORMAL,"locate_3dcnn input cloud empty");
  228. }
  229. if(mp_cnn3d==0)
  230. {
  231. return Error_manager(LOCATER_3DCNN_UNINIT,NORMAL,"locate_wheel 3dcnn is not init");
  232. }
  233. //识别车轮
  234. Error_manager code;
  235. code=mp_cnn3d->predict(cloud,center_x,center_y,wheel_base,width,angle,work_dir);
  236. if(code!=SUCCESS)
  237. {
  238. return code;
  239. }
  240. //根据plc限制判断合法性
  241. if(center_y>=930 || center_y<=200)
  242. {
  243. char description[255]={0};
  244. sprintf(description,"Y is out of range by plc (200 , 900) Y:%.2f",center_y);
  245. return Error_manager(LOCATER_Y_OUT_RANGE_BY_PLC,NORMAL,description);
  246. }
  247. return SUCCESS;
  248. }
  249. Error_manager Locater::measure_height(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_car,float& height)
  250. {
  251. if(cloud_car.get()==0)
  252. {
  253. return Error_manager(LOCATER_MEASURE_HEIGHT_CLOUD_UNINIT,NORMAL,"measure height input cloud uninit");
  254. }
  255. if(cloud_car->size()==0)
  256. {
  257. return Error_manager(LOCATER_MEASURE_HEIGHT_CLOUD_EMPTY,NORMAL,"measure height input cloud is empty");
  258. }
  259. pcl::PointXYZ min_point,max_point;
  260. pcl::getMinMax3D(*cloud_car,min_point,max_point);
  261. //限制车高的范围,检验结果
  262. height=max_point.z;
  263. // 20220111 changed by yct, height 1950
  264. if(height>=1950 || height<=1000)
  265. {
  266. char description[255]={0};
  267. sprintf(description,"height is out of range, retry :%.2f",height);
  268. return Error_manager(LOCATER_MEASURE_HEIGHT_OUT_RANGE,NORMAL,description);
  269. }
  270. return SUCCESS;
  271. }
  272. void Locater::save_cloud_txt(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,std::string save_file)
  273. {
  274. FILE* pfile=fopen(save_file.c_str(),"w");
  275. for(int i=0;i<cloud->size();++i)
  276. {
  277. fprintf(pfile,"%.3f %.3f %.3f\n",cloud->points[i].x,cloud->points[i].y,cloud->points[i].z);
  278. }
  279. fclose(pfile);
  280. }
  281. Error_manager Locater::locate(pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_src,
  282. Locate_information& locate_information, std::string work_dir)
  283. {
  284. if(cloud_src.get()==0)
  285. {
  286. return Error_manager(LOCATER_INPUT_CLOUD_UNINIT,NORMAL,"locate input cloud is not init");
  287. }
  288. if(cloud_src->size()==0) {
  289. return Error_manager(LOCATER_INPUT_CLOUD_EMPTY,NORMAL,"input cloud is empty");
  290. }
  291. //10mm网格过滤
  292. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
  293. /// ///体素网格 下采样
  294. pcl::VoxelGrid<pcl::PointXYZ> vgfilter;
  295. vgfilter.setInputCloud(cloud_src);
  296. vgfilter.setLeafSize(30.f, 30.f, 30.f);
  297. vgfilter.filter(*cloud_in);
  298. //保存原始点云 src.txt
  299. std::string src_cloud_file=work_dir+"/src.txt";
  300. save_cloud_txt(cloud_in,src_cloud_file);
  301. //置初始结果为错误
  302. locate_information.locate_correct=false;
  303. Error_manager code;
  304. //第一步 yolo定位车辆外接矩形
  305. std::vector<YoloBox> t_yolo_boxes;
  306. code=locate_yolo(cloud_in,t_yolo_boxes,work_dir);
  307. if(code!=SUCCESS)
  308. {
  309. return code;
  310. }
  311. //第二步 ,根据yolo框结合PointSift识别车身点云,第0类即轮胎,第二类为车身
  312. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_wheel(new pcl::PointCloud<pcl::PointXYZ>);
  313. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_car(new pcl::PointCloud<pcl::PointXYZ>);
  314. code=locate_sift(cloud_in,t_yolo_boxes,cloud_wheel,cloud_car,work_dir);
  315. // added by yct, 传出车轮点云,放入任务中替换完整点云
  316. cloud_src = cloud_wheel;
  317. if(code!=SUCCESS)
  318. {
  319. return code;
  320. }
  321. //第四步,识别轮胎,并根据轮胎数量计算旋转矩形
  322. float center_x;
  323. float center_y;
  324. float wheel_base;
  325. float width;
  326. float angle;
  327. code=locate_wheel(cloud_wheel,center_x,center_y,wheel_base,width,angle,work_dir);
  328. if(code!=SUCCESS)
  329. {
  330. return code;
  331. }
  332. //第三步,计算车辆高度
  333. // changed by yct, 传入完整点云而非仅车身点云
  334. // 20211207 changed by yct, 点云除去栏杆附近点计算高度
  335. float height_car=0;
  336. float height_car_filtered=0;
  337. // 计算x范围
  338. std::vector<Eigen::Vector2d> t_wheel_centers;
  339. float height_calc_offsetx = 100;
  340. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_car_height(new pcl::PointCloud<pcl::PointXYZ>);
  341. t_wheel_centers.push_back(Eigen::Vector2d(-(width+height_calc_offsetx)/2.0, wheel_base/2.0));
  342. t_wheel_centers.push_back(Eigen::Vector2d((width+height_calc_offsetx)/2.0, wheel_base/2.0));
  343. t_wheel_centers.push_back(Eigen::Vector2d(-(width+height_calc_offsetx)/2.0, -wheel_base/2.0));
  344. t_wheel_centers.push_back(Eigen::Vector2d((width+height_calc_offsetx)/2.0, -wheel_base/2.0));
  345. Eigen::Rotation2Dd t_rot((90.0-angle)*M_PI/180.0);
  346. double min_x=INT_MAX, max_x = 0.0;
  347. for (int i = 0; i < t_wheel_centers.size(); ++i) {
  348. t_wheel_centers[i] = t_rot.toRotationMatrix() * t_wheel_centers[i];
  349. if(min_x>t_wheel_centers[i].x())
  350. {
  351. min_x = t_wheel_centers[i].x();
  352. }
  353. if(max_x<t_wheel_centers[i].x())
  354. {
  355. max_x = t_wheel_centers[i].x();
  356. }
  357. }
  358. if(min_x<-width || max_x>width)
  359. {
  360. LOG(WARNING) << "min max x calc for height filter error, minx maxx: "<<min_x<<", "<<max_x;
  361. return Error_manager(LOCATER_MEASURE_HEIGHT_OUT_RANGE,NORMAL,"min max x calc error");
  362. }
  363. LOG(WARNING) << "min max x calc, minx maxx: "<<min_x+center_x<<", "<<max_x+center_x<<",,width: "<<width;
  364. for (int j = 0; j < cloud_in->size(); ++j) {
  365. if(cloud_in->points[j].x > (min_x+center_x) && cloud_in->points[j].x < (max_x+center_x))
  366. {
  367. cloud_car_height->push_back(cloud_in->points[j]);
  368. }
  369. }
  370. // 采用切除栏杆后点云计算车高
  371. code=measure_height(cloud_car_height,height_car_filtered);
  372. if(code!=SUCCESS)
  373. {
  374. return code;
  375. }
  376. locate_information.locate_hight=height_car_filtered;
  377. measure_height(cloud_in,height_car);
  378. LOG(WARNING)<< "height compare, origin---filtered: "<<height_car<<", "<<height_car_filtered<<"..cloud size:"<<cloud_car_height->size();
  379. //第六步,结果赋值
  380. //角度以度为单位
  381. // 20211223 added by yct, car height filtered become valid.
  382. locate_information.locate_x=center_x;
  383. locate_information.locate_y=center_y;
  384. locate_information.locate_theta = angle;
  385. locate_information.locate_length=wheel_base;
  386. locate_information.locate_width=width;
  387. locate_information.locate_hight=height_car_filtered;
  388. locate_information.locate_wheel_base=wheel_base;
  389. locate_information.locate_correct=true;
  390. LOG(INFO) << "Locate SUCCESS :" << " center:" << "[" << locate_information.locate_x
  391. << "," << locate_information.locate_y<< "] size= "
  392. << locate_information.locate_length << ", "
  393. << locate_information.locate_width << "," << locate_information.locate_hight
  394. << " angle=" << locate_information.locate_theta ;
  395. return SUCCESS;
  396. }