// // Created by zx on 2021/5/20. // #include "ground_region.h" #include #include #include #include #include #include "publisher.h" #include "point_tool.h" //欧式聚类******************************************************* std::vector::Ptr> Ground_region::segmentation(pcl::PointCloud::Ptr sor_cloud) { std::vector ece_inlier; pcl::search::KdTree::Ptr tree(new pcl::search::KdTree); pcl::EuclideanClusterExtraction ece; ece.setInputCloud(sor_cloud); ece.setClusterTolerance(0.07); ece.setMinClusterSize(20); ece.setMaxClusterSize(20000); ece.setSearchMethod(tree); ece.extract(ece_inlier); std::vector::Ptr> segmentation_clouds; for (int i = 0; i < ece_inlier.size(); i++) { pcl::PointCloud::Ptr cloud_copy(new pcl::PointCloud); std::vector ece_inlier_ext = ece_inlier[i].indices; copyPointCloud(*sor_cloud, ece_inlier_ext, *cloud_copy);//按照索引提取点云数据 segmentation_clouds.push_back(cloud_copy); } return segmentation_clouds; } double Ground_region::distance(cv::Point2f p1, cv::Point2f p2) { return sqrt(pow(p1.x - p2.x, 2.0) + pow(p1.y - p2.y, 2.0)); } bool Ground_region::isRect(std::vector& points) { if (points.size() == 4) { double L[3] = {0.0}; L[0] = distance(points[0], points[1]); L[1] = distance(points[1], points[2]); L[2] = distance(points[0], points[2]); double max_l = L[0]; double l1 = L[1]; double l2 = L[2]; cv::Point2f ps = points[0], pt = points[1]; cv::Point2f pc = points[2]; for (int i = 1; i < 3; ++i) { if (L[i] > max_l) { max_l = L[i]; l1 = L[abs(i + 1) % 3]; l2 = L[abs(i + 2) % 3]; ps = points[i % 3]; pt = points[(i + 1) % 3]; pc = points[(i + 2) % 3]; } } //直角边与坐标轴的夹角 <20° float thresh=20.0*M_PI/180.0; cv::Point2f vct(pt.x-pc.x,pt.y-pc.y); float angle=atan2(vct.y,vct.x); if(!(fabs(angle)= 0.15) { /*char description[255]={0}; sprintf(description,"angle cos value(%.2f) >0.13 ",cosa); std::cout<1.900 || length >3.300 ||length < 2.200) { /*char description[255]={0}; sprintf(description,"width<1400 || width >1900 || length >3300 ||length < 2200 l:%.1f,w:%.1f",length,width); std::cout< max_l * 0.1 || distance(center1, center2) > 0.150) { /*std::cout << "d:" << d << " maxl:" << max_l << " center1:" << center1 << " center2:" << center2< max_l * 0.1 || distance(center1, center2) > 0.150 "); std::cout< max_l) { max_index = i; max_l = L[i]; l1 = L[abs(i + 1) % 3]; l2 = L[abs(i + 2) % 3]; ps = points[i % 3]; pt = points[(i + 1) % 3]; pc = points[(i + 2) % 3]; } } //直角边与坐标轴的夹角 <20° float thresh=20.0*M_PI/180.0; cv::Point2f vct(pt.x-pc.x,pt.y-pc.y); float angle=atan2(vct.y,vct.x); if(!(fabs(angle)= 0.15) { /*char description[255]={0}; sprintf(description,"3 wheels angle cos value(%.2f) >0.13 ",cosa); std::cout<2.100 && l<3.300 && w>1.400 && w<2.100) { //生成第四个点 cv::Point2f vec1=ps-pc; cv::Point2f vec2=pt-pc; cv::Point2f point4=(vec1+vec2)+pc; points.push_back(point4); /*char description[255]={0}; sprintf(description,"3 wheels rectangle cos angle=%.2f,L=%.1f, w=%.1f",cosa,l,w); std::cout<::Ptr cloud,double thresh_z, detect_wheel_ceres3d::Detect_result& result) { if(m_detector== nullptr) return false; pcl::PointCloud::Ptr cloud_filtered(new pcl::PointCloud); for(int i=0;isize();++i) { pcl::PointXYZ pt=cloud->points[i]; if(pt.z< thresh_z) { cloud_filtered->push_back(pt); } } //下采样 pcl::VoxelGrid vox; //创建滤波对象 vox.setInputCloud(cloud_filtered); //设置需要过滤的点云给滤波对象 vox.setLeafSize(0.02f, 0.02f, 0.2f); //设置滤波时创建的体素体积为1cm的立方体 vox.filter(*cloud_filtered); //执行滤波处理,存储输出 if(cloud_filtered->size()==0) { return false; } if(cloud_filtered->size()==0) return false; pcl::StatisticalOutlierRemoval sor; //创建滤波器对象 sor.setInputCloud (cloud_filtered); //设置待滤波的点云 sor.setMeanK (5); //设置在进行统计时考虑的临近点个数 sor.setStddevMulThresh (3.0); //设置判断是否为离群点的阀值,用来倍乘标准差,也就是上面的std_mul sor.filter (*cloud_filtered); //滤波结果存储到cloud_filtered if(cloud_filtered->size()==0) { return false; } std::vector::Ptr> seg_clouds; seg_clouds=segmentation(cloud_filtered); if(!(seg_clouds.size()==4 || seg_clouds.size()==3)) { return false; } std::vector centers; for(int i=0;idetect(seg_clouds,result,error_str)) { return true; } else { return false; } } return ret; } Ground_region::~Ground_region() { m_exit_condition.set_pass_ever(true); // Close Capturte Thread if( m_running_thread && m_running_thread->joinable() ){ m_running_thread->join(); m_running_thread->~thread(); delete m_running_thread; m_running_thread = nullptr; } for(int i=0;iclose(); delete m_lidars[i]; } } m_lidars.clear(); if(m_detector) { delete m_detector; m_detector= nullptr; } } Ground_region::Ground_region() { m_detector= nullptr ; m_running_thread=nullptr; } Error_manager Ground_region::init(std::string configure_file) { if(read_proto_param(configure_file,m_configure)==false) { return Error_manager(FAILED,NORMAL,"read proto failed"); } pcl::PointCloud::Ptr left_model=ReadTxtCloud("/media/youchen/block_ntfs/yct/catkin_ws/src/feature_extra/left_model.txt"); // std::cout << "left model:" << left_model->size() << std::endl; pcl::PointCloud::Ptr right_model = ReadTxtCloud("/media/youchen/block_ntfs/yct/catkin_ws/src/feature_extra/right_model.txt"); // std::cout << "right model:" << right_model->size() << std::endl; m_detector=new detect_wheel_ceres3d(left_model,right_model); // std::cout << "????" << std::endl; return init(m_configure); } Error_manager Ground_region::init(ground_region::Configure configure) { //绑定通讯ip /*char connect_str[255]={0}; sprintf(connect_str,"tcp://%s:%d",configure.communication_cfg().ip().c_str(), configure.communication_cfg().port()); Publisher::get_instance_pointer()->communication_bind(connect_str); Publisher::get_instance_pointer()->communication_run(); //创建雷达 m_lidars.resize(configure.lidar_size()); for(int i=0;iisOpen() ){ char description[255]={0}; sprintf(description,"lidar [%d] open failed ip:%s ,port:%d",i,configure.lidar(i).ip().c_str(),port); return Error_manager(FAILED,NORMAL,description); } } */ m_configure=configure; m_running_thread=new std::thread(std::bind(thread_measure_func,this)); return SUCCESS; } bool Ground_region::read_proto_param(std::string file, ::google::protobuf::Message& parameter) { int fd = open(file.c_str(), O_RDONLY); if (fd == -1) return false; FileInputStream* input = new FileInputStream(fd); bool success = google::protobuf::TextFormat::Parse(input, ¶meter); delete input; close(fd); return success; } pcl::PointCloud::Ptr Ground_region::scans2cloud(const velodyne::Frame& frame, const ground_region::Calib_parameter& calib) { pcl::PointCloud::Ptr cloud(new pcl::PointCloud); for(int i=0;i::Ptr cloud_transpose(new pcl::PointCloud); pcl::transformPointCloud (*cloud, *cloud_transpose, transform_2); return cloud_transpose; } Error_manager Ground_region::sync_capture(std::vector::Ptr>& clouds,double timeout_second) { Tick timer; bool sync=false; clouds.clear(); std::vector sync_frames; while((false==m_exit_condition.wait_for_ex(std::chrono::microseconds(1))) && sync==false) { bool sync_once=true; for(int i=0;iget_frame(frame); if(frame.tic.tic()>0.2) { sync_frames.clear(); sync_once=false; break; } else { sync_frames.push_back(frame); } } if(timer.tic()>timeout_second) { return Error_manager(FAILED,NORMAL,"sync capture time out"); } sync=sync_once; usleep(1); } if(sync) { for(int i=0;i::Ptr cloud=(scans2cloud(sync_frames[i],m_configure.lidar(i).calib())); clouds.push_back(cloud); } return SUCCESS; } return FAILED; } Error_manager Ground_region::prehandle_cloud(std::vector::Ptr>& clouds, message::Ground_measure_statu_msg& msg) { if(msg.laser_statu_vector_size()!=m_lidars.size()) return ERROR; //直通滤波 ground_region::Box box = m_configure.box(); std::vector::Ptr> filtered_cloud_vector; for (int i = 0; i < clouds.size(); ++i) { pcl::PointCloud::Ptr cloud_filtered(new pcl::PointCloud); for (int j = 0; j < clouds[i]->size(); ++j) { pcl::PointXYZ pt = clouds[i]->points[j]; if (pt.x > box.minx() && pt.x < box.maxx() && pt.y > box.miny() && pt.y < box.maxy() && pt.z > box.minz() && pt.z < box.maxz()) { cloud_filtered->push_back(pt); } } filtered_cloud_vector.push_back(cloud_filtered); } //根据点云判断雷达状态,若所有雷达滤波后都有点, 则正常,lidar_statu_bit 各个位代表雷达是否有点, 有点为0,无点为1 int lidar_statu_bit = 0; for (int i = 0; i < filtered_cloud_vector.size(); ++i) { if (filtered_cloud_vector[i]->size() == 0) lidar_statu_bit |= (0x01 << i); else msg.set_laser_statu_vector(i, message::LASER_READY);//雷达正常 } if (lidar_statu_bit == 0) { clouds = filtered_cloud_vector; return SUCCESS; } //判断是否有雷达故障 for (int i = 0; i < filtered_cloud_vector.size(); ++i) { if (filtered_cloud_vector[i]->size() == 0) { //滤波之前也没有点,雷达故障 if (clouds[i]->size() == 0) { clouds = filtered_cloud_vector; msg.set_laser_statu_vector(i, message::LASER_DISCONNECT); return Error_manager(DISCONNECT, NORMAL, "雷达故障"); } } } //判断是不是所有雷达在该区域都没有点,表示该区域没有东西 int temp = 0; if (~(((~temp) << (filtered_cloud_vector.size())) | lidar_statu_bit) == 0) { clouds = filtered_cloud_vector; return Error_manager(POINT_EMPTY, NORMAL, "区域无点"); } else { clouds = filtered_cloud_vector; return Error_manager(CLOUD_INCOMPLETED, NORMAL, "点云不完整(雷达正常)"); } } bool computer_var(std::vector data,double& var) { if(data.size()==0) return false; Eigen::VectorXd dis_vec(data.size()); for(int i=0;i::Ptr cloud, const ground_region::Box& box,detect_wheel_ceres3d::Detect_result& last_result) { if(cloud->size()==0) return Error_manager(POINT_EMPTY,NORMAL,"no point"); pcl::PointCloud::Ptr cloud_filtered(new pcl::PointCloud); for(int i=0;isize();++i) { pcl::PointXYZ pt=cloud->points[i]; if(pt.x>box.minx()&&pt.xbox.miny()&&pt.ybox.minz()&&pt.zpush_back(pt); } } if(cloud_filtered->size()==0) return Error_manager(POINT_EMPTY,NORMAL,"filtered no point"); float start_z=box.minz(); float max_z=0.2; float center_z=(start_z+max_z)/2.0; float last_center_z=start_z; float last_succ_z=-1.0; int count=0; //二分法 找识别成功的 最高的z std::vector results; do { detect_wheel_ceres3d::Detect_result result; bool ret = classify_ceres_detect(cloud_filtered, center_z,result); // std::cout << "z: " << center_z <<", "< 0.01); // if(results.size()==0) { return Error_manager(FAILED,NORMAL,"nor car"); } /// to be float min_mean_loss=1.0; for(int i=0;i loss; loss.push_back(result.loss.lf_loss); loss.push_back(result.loss.rf_loss); loss.push_back(result.loss.lb_loss); loss.push_back(result.loss.rb_loss); double mean=(result.loss.lf_loss+result.loss.rf_loss+result.loss.lb_loss+result.loss.rb_loss)/4.0; double var=-1.; computer_var(loss,var); if(meansave_debug_data("/home/zx/zzw/catkin_ws/src/feature_extra/debug"); return SUCCESS; } #include "message/message_base.pb.h" void Ground_region::thread_measure_func(Ground_region* p) { return ; message::Ground_measure_statu_msg msg; message::Base_info base_info; base_info.set_msg_type(message::eGround_measure_statu_msg); base_info.set_sender(message::eEmpty); base_info.set_receiver(message::eEmpty); msg.mutable_base_info()->CopyFrom(base_info); msg.set_ground_statu(message::Nothing); const float fps=10.; //保持 10 fps while(false==p->m_exit_condition.wait_for_millisecond(int(1000./fps))) { for(int i=0;im_lidars.size();++i) { msg.add_laser_statu_vector( p->m_lidars[i]->isRun()?message::LASER_READY:message::LASER_DISCONNECT); } std::vector::Ptr> clouds; Error_manager code=p->sync_capture(clouds,0.5); if(code!=SUCCESS) { LOG(WARNING)<prehandle_cloud(clouds,msg); if(code!=SUCCESS) { LOG(WARNING)<::Ptr correct_cloud(new pcl::PointCloud); for(int i=0;idetect(correct_cloud,p->m_configure.box(),result); if(tick.tic()>1./fps) { LOG(WARNING)<<" detect fps < capture fps"; } if(code!=SUCCESS) { LOG_EVERY_N(INFO,20)<publish_msg(&c_msg); } }