region_detect.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. //
  2. // Created by zx on 2019/12/6.
  3. //
  4. #include "region_detect.h"
  5. /**
  6. * 有参构造函数
  7. * */
  8. Region_detector::Region_detector()
  9. {
  10. }
  11. /**
  12. * 析构函数
  13. * */
  14. Region_detector::~Region_detector()
  15. {
  16. }
  17. Error_manager Region_detector::init(Point2D_tool::Point2D_box point2D_box)
  18. {
  19. m_region_box = point2D_box;
  20. return Error_code::SUCCESS;
  21. }
  22. /**
  23. * 预处理,xy直通滤波与离群点过滤
  24. * 返回 PARAMETER_ERROR,WJ_REGION_EMPTY_CLOUD 或 SUCCESS
  25. * */
  26. Error_manager Region_detector::preprocess(pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud)
  27. {
  28. // 1.参数合法性检验
  29. if (p_cloud->size() <= 0)
  30. return Error_manager(Error_code::WJ_REGION_EMPTY_CLOUD);
  31. // std::cout<<"preprocess 000"<<std::endl;
  32. // 2.直通滤波, 筛选xy
  33. pcl::PassThrough<pcl::PointXYZ> pass;
  34. pass.setInputCloud(p_cloud);
  35. pass.setFilterFieldName("x"); //设置想在哪个坐标轴上操作
  36. pass.setFilterLimits(m_region_box.x_min, m_region_box.x_max); //将x轴的0到1范围内
  37. pass.setFilterLimitsNegative(false); //保留(true就是删除,false就是保留而删除此区间外的)
  38. pass.filter(*p_cloud); //输出到结果指针
  39. if (p_cloud->size() <= 0)
  40. return Error_manager(Error_code::WJ_REGION_EMPTY_CLOUD);
  41. // std::cout<<"preprocess 111 "<<p_cloud->size()<<std::endl;
  42. pass.setInputCloud(p_cloud);
  43. pass.setFilterFieldName("y"); //设置想在哪个坐标轴上操作
  44. pass.setFilterLimits(m_region_box.y_min, m_region_box.y_max); //将x轴的0到1范围内
  45. pass.setFilterLimitsNegative(false); //保留(true就是删除,false就是保留而删除此区间外的)
  46. pass.filter(*p_cloud); //输出到结果指针
  47. // std::cout << "cloud size: "<<p_cloud->size()<<","<<m_region_box.x_min<<","<<m_region_box.x_max<<","<<m_region_box.y_min<<","<<m_region_box.y_max<<std::endl;
  48. if (p_cloud->size() <= 0)
  49. return Error_manager(Error_code::WJ_REGION_EMPTY_CLOUD);
  50. // std::cout<<"preprocess 222 "<<p_cloud->size()<<std::endl;
  51. // 3.离群点过滤
  52. pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
  53. sor.setInputCloud(p_cloud);
  54. sor.setMeanK(15); //K近邻搜索点个数
  55. sor.setStddevMulThresh(3.0); //标准差倍数
  56. sor.setNegative(false); //保留未滤波点(内点)
  57. sor.filter(*p_cloud); //保存滤波结果到cloud_filter
  58. // std::cout<<"preprocess 333 "<<p_cloud->size()<<std::endl;
  59. if (p_cloud->size() <= 0)
  60. return Error_manager(Error_code::WJ_REGION_EMPTY_CLOUD);
  61. else
  62. return Error_manager(Error_code::SUCCESS);
  63. }
  64. /**
  65. * 返回二维点之间距离
  66. * */
  67. double Region_detector::distance(cv::Point2f p1, cv::Point2f p2)
  68. {
  69. return sqrt(pow(p1.x - p2.x, 2.0) + pow(p1.y - p2.y, 2.0));
  70. }
  71. /**
  72. * 判断是否符合标准矩形,
  73. * 传入矩形四个角点,以及是否打印
  74. * 返回 WJ_REGION_RECTANGLE_ANGLE_ERROR, WJ_REGION_RECTANGLE_SIZE_ERROR,
  75. * WJ_REGION_RECTANGLE_SYMMETRY_ERROR, WJ_REGION_CLUSTER_SIZE_ERROR, SUCCESS
  76. * */
  77. Error_manager Region_detector::isRect(std::vector<cv::Point2f> &points, bool print)
  78. {
  79. if (points.size() == 4)
  80. {
  81. double L[3] = {0.0};
  82. L[0] = distance(points[0], points[1]);
  83. L[1] = distance(points[1], points[2]);
  84. L[2] = distance(points[0], points[2]);
  85. double max_l = L[0];
  86. double l1 = L[1];
  87. double l2 = L[2];
  88. int max_index = 0;
  89. cv::Point2f ps = points[0], pt = points[1];
  90. // 顶点
  91. cv::Point2f pc = points[2];
  92. for (int i = 1; i < 3; ++i)
  93. {
  94. if (L[i] > max_l)
  95. {
  96. max_index = i;
  97. max_l = L[i];
  98. l1 = L[abs(i + 1) % 3];
  99. l2 = L[abs(i + 2) % 3];
  100. ps = points[i % 3];
  101. pt = points[(i + 1) % 3];
  102. pc = points[(i + 2) % 3];
  103. }
  104. }
  105. // 顶角大小
  106. double cosa = (l1 * l1 + l2 * l2 - max_l * max_l) / (2.0 * l1 * l2);
  107. // 顶角相对于90度过大或小
  108. if (fabs(cosa) >= 0.15 /* || std::min(l1, l2) > 2.0 || std::max(l1, l2) > 3.3*/)
  109. {
  110. if (print)
  111. {
  112. LOG(WARNING) << " angle cos >0.13 =" << cosa << " i=" << max_index;
  113. // LOG(WARNING) << "L1:" << l1 << " L2:" << l2 << " L3:" << max_l;
  114. }
  115. return Error_manager(Error_code::WJ_REGION_RECTANGLE_ANGLE_ERROR);
  116. }
  117. float width = std::min(l1, l2);
  118. float length = std::max(l1, l2);
  119. // 车宽应位于[1.35, 2.0],车长应位于[2.2, 3.0]
  120. if (width < 1.350 || width > 2.000 || length > 3.000 || length < 2.200)
  121. {
  122. if (print)
  123. {
  124. LOG(WARNING) << "\t width<1350 || width >2100 || length >3300 ||length < 2100 "
  125. << " length:" << length << " width:" << width;
  126. }
  127. return Error_manager(Error_code::WJ_REGION_RECTANGLE_SIZE_ERROR);
  128. }
  129. double d = distance(pc, points[3]);
  130. cv::Point2f center1 = (ps + pt) * 0.5;
  131. cv::Point2f center2 = (pc + points[3]) * 0.5;
  132. // 对角线形变超过0.15倍,或中心点距离偏差0.15m
  133. if (fabs(d - max_l) > max_l * 0.15 || distance(center1, center2) > 0.150)
  134. {
  135. if (print)
  136. {
  137. LOG(WARNING) << "d:" << d << " maxl:" << max_l << " center1:" << center1 << " center2:" << center2
  138. << " center distance=" << distance(center1, center2);
  139. }
  140. return Error_manager(Error_code::WJ_REGION_RECTANGLE_SYMMETRY_ERROR);
  141. }
  142. if (print)
  143. {
  144. LOG(INFO) << " rectangle verify OK cos angle=" << cosa << " length off=" << fabs(d - max_l)
  145. << " center distance=" << distance(center1, center2);
  146. }
  147. return Error_manager(Error_code::SUCCESS);
  148. }
  149. // 以三个点进行验证
  150. else if (points.size() == 3)
  151. {
  152. double L[3] = {0.0};
  153. L[0] = distance(points[0], points[1]);
  154. L[1] = distance(points[1], points[2]);
  155. L[2] = distance(points[0], points[2]);
  156. double max_l = L[0];
  157. double l1 = L[1];
  158. double l2 = L[2];
  159. int max_index = 0;
  160. cv::Point2f ps = points[0], pt = points[1];
  161. cv::Point2f pc = points[2];
  162. for (int i = 1; i < 3; ++i)
  163. {
  164. if (L[i] > max_l)
  165. {
  166. max_index = i;
  167. max_l = L[i];
  168. l1 = L[abs(i + 1) % 3];
  169. l2 = L[abs(i + 2) % 3];
  170. ps = points[i % 3];
  171. pt = points[(i + 1) % 3];
  172. pc = points[(i + 2) % 3];
  173. }
  174. }
  175. double cosa = (l1 * l1 + l2 * l2 - max_l * max_l) / (2.0 * l1 * l2);
  176. // 顶角应接近90度
  177. if (fabs(cosa) >= 0.15)
  178. {
  179. if (print)
  180. {
  181. LOG(WARNING) << "3 wheels angle cos >0.12 =" << cosa << " i=" << max_index;
  182. LOG(WARNING) << "L1:" << l1 << " L2:" << l2 << " L3:" << max_l;
  183. }
  184. return Error_manager(Error_code::WJ_REGION_RECTANGLE_ANGLE_ERROR);
  185. }
  186. double length = std::max(l1, l2);
  187. double width = std::min(l1, l2);
  188. // 车宽应位于[1.4, 2.0],车长应位于[2.2, 3.0]
  189. if (length > 2.100 && length < 3.000 && width > 1.400 && width < 2.100)
  190. {
  191. //生成第四个点
  192. cv::Point2f vec1 = ps - pc;
  193. cv::Point2f vec2 = pt - pc;
  194. cv::Point2f point4 = (vec1 + vec2) + pc;
  195. points.push_back(point4);
  196. if (print)
  197. {
  198. LOG(WARNING) << "3 wheels rectangle verify OK cos angle=" << cosa << " L=" << length
  199. << " w=" << width;
  200. }
  201. return Error_manager(Error_code::SUCCESS);
  202. }
  203. else
  204. {
  205. if (print)
  206. {
  207. LOG(WARNING) << "3 wheels rectangle verify Failed cos angle=" << cosa << " L=" << length
  208. << " w=" << width;
  209. }
  210. return Error_manager(Error_code::WJ_REGION_RECTANGLE_SIZE_ERROR);
  211. }
  212. }
  213. else
  214. {
  215. return Error_manager(Error_code::WJ_REGION_CLUSTER_SIZE_ERROR);
  216. }
  217. }
  218. /*
  219. * 仅仅聚类
  220. */
  221. Error_manager Region_detector::clustering_only(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in,
  222. std::vector<pcl::PointCloud<pcl::PointXYZ>> &seg_clouds, bool print)
  223. {
  224. // 1.判断参数合法性
  225. if (cloud_in->size() <= 0)
  226. return Error_manager(Error_code::WJ_REGION_EMPTY_CLOUD);
  227. // 2.聚类
  228. pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
  229. kdtree->setInputCloud(cloud_in);
  230. pcl::EuclideanClusterExtraction<pcl::PointXYZ> clustering;
  231. // 设置聚类的最小值 2cm (small values may cause objects to be divided
  232. // in several clusters, whereas big values may join objects in a same cluster).
  233. clustering.setClusterTolerance(0.5);
  234. // 设置聚类的小点数和最大点云数
  235. clustering.setMinClusterSize(10);
  236. clustering.setMaxClusterSize(500);
  237. clustering.setSearchMethod(kdtree);
  238. clustering.setInputCloud(cloud_in);
  239. std::vector<pcl::PointIndices> clusters;
  240. clustering.extract(clusters);
  241. if(clusters.size() <= 0)
  242. return Error_manager(Error_code::WJ_REGION_EMPTY_CLOUD);
  243. for (int i = 0; i < clusters.size(); ++i)
  244. {
  245. seg_clouds.push_back(pcl::PointCloud<pcl::PointXYZ>());
  246. }
  247. int j = 0;
  248. for (std::vector<pcl::PointIndices>::const_iterator it = clusters.begin(); it != clusters.end(); ++it)
  249. {
  250. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZ>);
  251. //创建新的点云数据集cloud_cluster,将所有当前聚类写入到点云数据集中
  252. for (std::vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); ++pit)
  253. {
  254. cloud_cluster->points.push_back(cloud_in->points[*pit]);
  255. cloud_cluster->width = cloud_cluster->points.size();
  256. cloud_cluster->height = 1;
  257. cloud_cluster->is_dense = true;
  258. }
  259. seg_clouds[j] = *cloud_cluster;
  260. j++;
  261. }
  262. if (print)
  263. {
  264. LOG(INFO) << " cluster classes:" << clusters.size();
  265. }
  266. return SUCCESS;
  267. }
  268. /**
  269. * 聚类并通过矩形判断函数
  270. * 传入原始点云,传出角点与聚类出的点云
  271. * 返回 WJ_REGION_EMPTY_CLOUD, WJ_REGION_RECTANGLE_ANGLE_ERROR, WJ_REGION_RECTANGLE_SIZE_ERROR,
  272. * WJ_REGION_RECTANGLE_SYMMETRY_ERROR, WJ_REGION_CLUSTER_SIZE_ERROR, SUCCESS
  273. * */
  274. Error_manager Region_detector::clustering(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in, std::vector<cv::Point2f> &corner_points, std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> &seg_clouds, bool print)
  275. {
  276. // 1.判断参数合法性
  277. if (cloud_in->size() <= 0)
  278. return Error_manager(Error_code::WJ_REGION_EMPTY_CLOUD);
  279. // 2.聚类
  280. pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
  281. kdtree->setInputCloud(cloud_in);
  282. pcl::EuclideanClusterExtraction<pcl::PointXYZ> clustering;
  283. // 设置聚类的最小值 2cm (small values may cause objects to be divided
  284. // in several clusters, whereas big values may join objects in a same cluster).
  285. clustering.setClusterTolerance(0.2);
  286. // 设置聚类的小点数和最大点云数
  287. clustering.setMinClusterSize(10);
  288. clustering.setMaxClusterSize(500);
  289. clustering.setSearchMethod(kdtree);
  290. clustering.setInputCloud(cloud_in);
  291. std::vector<pcl::PointIndices> clusters;
  292. clustering.extract(clusters);
  293. if(clusters.size() <= 0)
  294. return Error_manager(Error_code::WJ_REGION_EMPTY_CLOUD);
  295. for (int i = 0; i < clusters.size(); ++i)
  296. {
  297. seg_clouds.push_back(pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>));
  298. }
  299. int j = 0;
  300. for (std::vector<pcl::PointIndices>::const_iterator it = clusters.begin(); it != clusters.end(); ++it)
  301. {
  302. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZ>);
  303. //创建新的点云数据集cloud_cluster,将所有当前聚类写入到点云数据集中
  304. for (std::vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); ++pit)
  305. {
  306. cloud_cluster->points.push_back(cloud_in->points[*pit]);
  307. cloud_cluster->width = cloud_cluster->points.size();
  308. cloud_cluster->height = 1;
  309. cloud_cluster->is_dense = true;
  310. }
  311. seg_clouds[j] = cloud_cluster;
  312. j++;
  313. }
  314. if (print)
  315. {
  316. LOG(INFO) << " cluster classes:" << clusters.size();
  317. }
  318. // 3.分别计算每团点云几何中心,作为矩形角点
  319. corner_points.clear();
  320. for (int i = 0; i < clusters.size(); ++i)
  321. {
  322. if (seg_clouds.size() <= i || seg_clouds[i]->size() == 0)
  323. continue;
  324. float sumX = 0, sumY = 0;
  325. for (int j = 0; j < seg_clouds[i]->size(); ++j)
  326. {
  327. sumX += seg_clouds[i]->points[j].x;
  328. sumY += seg_clouds[i]->points[j].y;
  329. }
  330. float center_x = sumX / float(seg_clouds[i]->size());
  331. float center_y = sumY / float(seg_clouds[i]->size());
  332. corner_points.push_back(cv::Point2f(center_x, center_y));
  333. }
  334. /*char buf[255]={0};
  335. for (int k = 0; k < corner_points.size(); ++k) {
  336. sprintf(buf+strlen(buf), "point %d: (%.2f, %.2f)__", k, corner_points[k].x, corner_points[k].y);
  337. }
  338. LOG(WARNING) << buf;*/
  339. cv::RotatedRect t_rect=cv::minAreaRect(corner_points);
  340. //display(t_rect,cv::Scalar(255,0,0));
  341. return isRect(corner_points, print);
  342. }
  343. // 检测传入点云,识别为四类返回中心点、角度、轮距与宽度
  344. Error_manager Region_detector::detect(std::mutex* p_cloud_mutex, pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_in,
  345. Common_data::Car_wheel_information& car_wheel_information, bool print)
  346. {
  347. //整个函数都加锁, 这里面非法修改了输入点云, 是为了将筛选点云的结构传出, 然后点云存txt文件
  348. std::unique_lock<std::mutex> t_lock(*p_cloud_mutex);
  349. Error_manager result = Error_manager(Error_code::SUCCESS);
  350. pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
  351. *p_cloud_filtered = *p_cloud_in;
  352. // 1.预处理
  353. result = preprocess(p_cloud_filtered);
  354. if (result != SUCCESS)
  355. return result;
  356. // 2.聚类计算角点
  357. std::vector<cv::Point2f> corner_points;
  358. std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> seg_clouds;
  359. result = clustering(p_cloud_filtered, corner_points, seg_clouds, print);
  360. if (result != SUCCESS)
  361. return result;
  362. // 修改原始点云为预处理后点云,并加入角点供查验
  363. p_cloud_in->clear();
  364. p_cloud_in->operator+=(*p_cloud_filtered);
  365. for (size_t i = 0; i < corner_points.size(); i++)
  366. {
  367. p_cloud_in->points.push_back(pcl::PointXYZ(corner_points[i].x, corner_points[i].y, 0.0));
  368. }
  369. // convert all points after preprocessed into 2d
  370. std::vector<cv::Point2f> all_points;
  371. // car center
  372. for (int j = 0; j < p_cloud_filtered->size(); ++j)
  373. {
  374. all_points.push_back(cv::Point2f(p_cloud_filtered->points[j].x, p_cloud_filtered->points[j].y));
  375. }
  376. // find bounding rectangle of all wheel points
  377. cv::RotatedRect wheel_box = cv::minAreaRect(all_points);
  378. car_wheel_information.car_center_x = wheel_box.center.x;
  379. car_wheel_information.car_center_y = wheel_box.center.y;
  380. // add center point to the input cloud for further check
  381. p_cloud_in->points.push_back(pcl::PointXYZ(car_wheel_information.car_center_x, car_wheel_information.car_center_y, 0.0));
  382. // 长边向量
  383. cv::Point2f vec;
  384. cv::Point2f vertice[4];
  385. wheel_box.points(vertice);
  386. float len1 = pow(vertice[0].x - vertice[1].x, 2.0) + pow(vertice[0].y - vertice[1].y, 2.0);
  387. float len2 = pow(vertice[1].x - vertice[2].x, 2.0) + pow(vertice[1].y - vertice[2].y, 2.0);
  388. // 寻找长边,倾角为长边与x轴夹角
  389. if (len1 > len2)
  390. {
  391. vec.x = vertice[0].x - vertice[1].x;
  392. vec.y = vertice[0].y - vertice[1].y;
  393. }
  394. else
  395. {
  396. vec.x = vertice[1].x - vertice[2].x;
  397. vec.y = vertice[1].y - vertice[2].y;
  398. }
  399. float angle_x = 180.0 / M_PI * acos(vec.x / sqrt(vec.x * vec.x + vec.y * vec.y));
  400. car_wheel_information.car_angle = angle_x;
  401. // get line formula, normal is (cos(theta), sin(theta)), towards the long side
  402. // the line formula is: nx * x + ny * y + (-(nx*cx+ny*cy)) = 0
  403. Eigen::Vector2f normal, center_point;
  404. normal << vec.x / sqrt(vec.x * vec.x + vec.y * vec.y), vec.y / sqrt(vec.x * vec.x + vec.y * vec.y);
  405. center_point << car_wheel_information.car_center_x, car_wheel_information.car_center_y;
  406. float line_param_c = -1 * center_point.transpose() * normal;
  407. // get rotation matrix, get the angle towards normal vector, rather than x axis
  408. // R = [ cos -sin]
  409. // [ sin cos]
  410. float rotate_angle = M_PI_2 - acos(vec.x / sqrt(vec.x * vec.x + vec.y * vec.y));
  411. Eigen::Matrix2f rotation_matrix;
  412. rotation_matrix << cos(rotate_angle), -sin(rotate_angle), sin(rotate_angle), cos(rotate_angle);
  413. // find min x and max x, separate y values according to the line, calculate difference between mean of y values as wheelbase
  414. float min_x = 20, max_x = 0;
  415. float y_values0 = 0, y_values1 = 0;
  416. int count0 = 0, count1 = 0;
  417. for (size_t i = 0; i < seg_clouds.size(); i++)
  418. {
  419. if (seg_clouds[i]->size() <= 0)
  420. continue;
  421. for (size_t j = 0; j < seg_clouds[i]->size(); j++)
  422. {
  423. // origin point and the point rotated around the origin
  424. Eigen::Vector2f vec, vec_rot;
  425. vec << seg_clouds[i]->points[j].x, seg_clouds[i]->points[j].y;
  426. vec_rot = rotation_matrix * (vec - center_point) + center_point;
  427. // find min max x
  428. if (vec_rot[0] < min_x)
  429. min_x = vec_rot[0];
  430. if (vec_rot[0] > max_x)
  431. max_x = vec_rot[0];
  432. // separate point as two clusters(front and back), calc y values respectively
  433. if (normal.transpose() * vec + line_param_c > 0)
  434. {
  435. y_values0 += vec_rot[1];
  436. count0 += 1;
  437. }
  438. else
  439. {
  440. y_values1 += vec_rot[1];
  441. count1 += 1;
  442. }
  443. }
  444. }
  445. // check if front and back both has points
  446. if (count0 > 0 && count1 > 0)
  447. {
  448. y_values0 /= count0;
  449. y_values1 /= count1;
  450. car_wheel_information.car_wheel_base = fabs(y_values1 - y_values0);
  451. car_wheel_information.car_wheel_width = fabs(min_x - max_x);
  452. // LOG(INFO) << "--------detector find width, wheelbase: " << width << ", " << wheelbase << ", y means: [" << y_values0 << ", " << y_values1 << "] -----";
  453. p_cloud_in->points.push_back(pcl::PointXYZ(min_x, car_wheel_information.car_center_y, 0.0));
  454. p_cloud_in->points.push_back(pcl::PointXYZ(max_x, car_wheel_information.car_center_y, 0.0));
  455. p_cloud_in->points.push_back(pcl::PointXYZ(car_wheel_information.car_center_x, y_values0, 0.0));
  456. p_cloud_in->points.push_back(pcl::PointXYZ(car_wheel_information.car_center_x, y_values1, 0.0));
  457. }
  458. else
  459. {
  460. // calculate wheelbase according to corner points
  461. // wheelbase = std::max(wheel_box.size.width, wheel_box.size.height);
  462. // LOG(INFO) << "--------detector find border: [" << wheel_box.size.width << ", " << wheel_box.size.height << "] -----";
  463. cv::RotatedRect wheel_center_box = cv::minAreaRect(corner_points);
  464. car_wheel_information.car_wheel_base = std::max(wheel_center_box.size.width, wheel_center_box.size.height);
  465. car_wheel_information.car_wheel_width = std::min(wheel_box.size.width, wheel_box.size.height);
  466. }
  467. return Error_manager(Error_code::SUCCESS);
  468. }
  469. //通过ceres检测中心,旋转,轴距,宽度, 新算法, 可以测量前轮旋转
  470. Error_manager Region_detector::detect_ex(std::mutex* p_cloud_mutex, pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_in,
  471. Common_data::Car_wheel_information& car_wheel_information, bool print)
  472. {
  473. Error_manager result = Error_manager(Error_code::SUCCESS);
  474. pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
  475. {
  476. std::unique_lock<std::mutex> t_lock(*p_cloud_mutex);
  477. *p_cloud_filtered = *p_cloud_in;
  478. }
  479. // 1.预处理
  480. result = preprocess(p_cloud_filtered);
  481. if (result != SUCCESS)
  482. return result;
  483. // std::cout << " huli test :::: " << " 111 = " << 111 << std::endl;
  484. // 2.聚类
  485. std::vector<pcl::PointCloud<pcl::PointXYZ>> seg_clouds;
  486. result = clustering_only(p_cloud_filtered, seg_clouds, print);
  487. if (result != SUCCESS)
  488. return result;
  489. // std::cout << " huli test :::: " << " 112 = " << 112 << std::endl;
  490. detect_wheel_ceres::Detect_result detect_result;
  491. std::string t_error_info;
  492. if(!m_detector_ceres.detect(seg_clouds, detect_result, t_error_info))
  493. {
  494. return Error_manager(Error_code::WJ_REGION_CERES_SOLVE_ERROR, MINOR_ERROR, t_error_info.c_str());
  495. }
  496. else
  497. {
  498. std::unique_lock<std::mutex> t_lock(*p_cloud_mutex);
  499. car_wheel_information.car_center_x = detect_result.cx;
  500. car_wheel_information.car_center_y = detect_result.cy;
  501. car_wheel_information.car_angle = detect_result.theta;
  502. car_wheel_information.car_wheel_base = detect_result.wheel_base;
  503. car_wheel_information.car_wheel_width = detect_result.width;
  504. car_wheel_information.car_front_theta = detect_result.front_theta;
  505. car_wheel_information.correctness = detect_result.success;
  506. }
  507. return Error_manager(Error_code::SUCCESS);
  508. }