|
@@ -3,8 +3,10 @@
|
|
|
//
|
|
|
|
|
|
#include "locater.h"
|
|
|
+#include <pcl/filters//voxel_grid.h>
|
|
|
+#include <pcl/filters/passthrough.h>
|
|
|
#include <glog/logging.h>
|
|
|
-Locater::Locater()
|
|
|
+Locater::Locater():mp_yolo_detector(0),mp_point_sift(0),mp_cnn3d(0)
|
|
|
{
|
|
|
}
|
|
|
Locater::~Locater()
|
|
@@ -29,10 +31,10 @@ ERROR_CODE Locater::init(LidarMeasure::LocateParameter parameter)
|
|
|
std::string graph_file = graph;
|
|
|
std::string cpkt_file = cpkt;
|
|
|
LOG(INFO)<<"init pointSift net ...";
|
|
|
- code=mp_point_sift->Init(graph_file,cpkt_file);
|
|
|
+ code=mp_point_sift->init(graph_file,cpkt_file);
|
|
|
if(code!=SUCCESS)
|
|
|
{
|
|
|
- LOG(ERROR)<<"Init pointSIFT net Failed ... exit";
|
|
|
+ LOG(ERROR)<<"Init pointSIFT net Failed ... "<<code;
|
|
|
return code;
|
|
|
}
|
|
|
}
|
|
@@ -56,35 +58,313 @@ ERROR_CODE Locater::init(LidarMeasure::LocateParameter parameter)
|
|
|
int nClass = parameter.net_3dcnn_parameter().nclass();
|
|
|
int freq = parameter.net_3dcnn_parameter().freq();
|
|
|
|
|
|
- LOG(INFO)<<"Creating 3dcnn ...";
|
|
|
mp_cnn3d = new Cnn3d_segmentation(l, w, h, freq, nClass);
|
|
|
|
|
|
LOG(INFO)<<"Init 3dcnn ...";
|
|
|
std::string weights = parameter.net_3dcnn_parameter().weights_file();
|
|
|
- code=mp_cnn3d->Init(weights);
|
|
|
+ code=mp_cnn3d->init(weights);
|
|
|
if(SUCCESS!=code)
|
|
|
{
|
|
|
- LOG(ERROR)<<"Init 3dcnn failed exit : ";
|
|
|
+ LOG(ERROR)<<"Init 3dcnn failed : "<<code;
|
|
|
return code;
|
|
|
}
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
-ERROR_CODE Locater::execute_task(Locate_task* task,double time_out)
|
|
|
+ERROR_CODE Locater::execute_task(Task_Base* task,double time_out)
|
|
|
{
|
|
|
+ LOG(INFO)<<"NEW LOCATE TASK ==============================================================================";
|
|
|
+ Locate_information locate_information;
|
|
|
+ locate_information.locate_correct=false;
|
|
|
+
|
|
|
//判断task是否合法
|
|
|
if(task==0) return LOCATER_TASK_ERROR;
|
|
|
if(task->get_task_type()!=LOCATE_TASK)
|
|
|
{
|
|
|
+ LOG(ERROR)<<"locate Task type error";
|
|
|
+ task->update_statu(TASK_OVER,"locate task type error");
|
|
|
return LOCATER_TASK_ERROR;
|
|
|
}
|
|
|
+ Locate_task* locate_task=(Locate_task*)task;
|
|
|
+ ERROR_CODE code;
|
|
|
+ ///第一步,获取task中input点云,文件保存路径
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr t_cloud_input=locate_task->get_locate_cloud();
|
|
|
+ std::string save_path=locate_task->get_save_path();
|
|
|
+ if(t_cloud_input.get()==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"Task set cloud is uninit";
|
|
|
+ locate_task->update_statu(TASK_OVER,"Task set cloud is uninit");
|
|
|
+ return LOCATER_INPUT_CLOUD_UNINIT;
|
|
|
+ }
|
|
|
+ //第二步,调用locate
|
|
|
+ code=locate(t_cloud_input,locate_information,save_path);
|
|
|
+ if(SUCCESS!=code)
|
|
|
+ {
|
|
|
+ locate_task->update_statu(TASK_OVER,"Locate Failed");
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+ locate_task->set_locate_information(locate_information);
|
|
|
+ locate_task->update_statu(TASK_OVER,"Locate OK");
|
|
|
+ return code;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+ERROR_CODE Locater::locate_yolo(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in,
|
|
|
+ std::vector<YoloBox>& boxes, std::string work_dir)
|
|
|
+{
|
|
|
+ if(cloud_in.get()==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"yolo input cloud uninit";
|
|
|
+ return LOCATER_YOLO_INPUT_CLOUD_UNINIT;
|
|
|
+ }
|
|
|
+ if(cloud_in->size()==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"locate_yolo input cloud empty";
|
|
|
+ return LOCATER_INPUT_YOLO_CLOUD_EMPTY;
|
|
|
+ }
|
|
|
+ if(mp_yolo_detector==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"locate_yolo yolo is not init";
|
|
|
+ return LOCATER_YOLO_UNINIT;
|
|
|
+ }
|
|
|
+ //1,根据点云区域,调整yolo边界参数,边界参数必须保证长宽 1:1
|
|
|
+ pcl::PointXYZ min_point,max_point;
|
|
|
+ pcl::getMinMax3D(*cloud_in,min_point,max_point);
|
|
|
+ float yolo_minx=min_point.x;
|
|
|
+ float yolo_maxx=max_point.x;
|
|
|
+ float yolo_miny=min_point.y;
|
|
|
+ float yolo_maxy=max_point.y;
|
|
|
+ float length=yolo_maxx-yolo_minx;
|
|
|
+ float width=yolo_maxy-yolo_miny;
|
|
|
+ if(length>2*width) yolo_maxy=(length/2.0)+yolo_miny;
|
|
|
+ else if(length<2*width) yolo_maxx=(2*width)+yolo_minx;
|
|
|
+
|
|
|
+ LOG(INFO)<<("set yolo parameter l:%.3f r:%.3f t:%.3f b:%.3f\n",
|
|
|
+ yolo_minx,yolo_maxx,yolo_miny,yolo_maxy);
|
|
|
+ mp_yolo_detector->set_region(yolo_minx,yolo_maxx,yolo_miny,yolo_maxy,m_locate_parameter.yolo_parameter().freq());
|
|
|
+ //2,识别车辆位置
|
|
|
+ boxes.clear();
|
|
|
+ ERROR_CODE code=mp_yolo_detector->detect(cloud_in,boxes,work_dir);
|
|
|
+ if(code!=SUCCESS)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"Yolo detect failed : "<<code;
|
|
|
+ }
|
|
|
+ return code;
|
|
|
+}
|
|
|
+
|
|
|
+ERROR_CODE Locater::locate_sift(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in, std::vector<YoloBox> boxes,
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_targe, std::string work_dir)
|
|
|
+{
|
|
|
+ if(cloud_in.get()==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"sift input cloud uninit";
|
|
|
+ return LOCATER_SIFT_INPUT_CLOUD_UNINIT;
|
|
|
+ }
|
|
|
+ if(cloud_in->size()==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"locate_sift input cloud empty";
|
|
|
+ return LOCATER_SIFT_INPUT_CLOUD_EMPTY;
|
|
|
+ }
|
|
|
+ if(mp_point_sift==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"Point Sift unInit ";
|
|
|
+ return LOCATER_POINTSIFT_UNINIT;
|
|
|
+ }
|
|
|
+ //第一步,根据点云边界调整PointSIft 参数
|
|
|
+ pcl::PointXYZ min_point,max_point;
|
|
|
+ pcl::getMinMax3D(*cloud_in,min_point,max_point);
|
|
|
+ ERROR_CODE code ;
|
|
|
+ code=mp_point_sift->set_region(min_point,max_point);
|
|
|
+ if(code!=SUCCESS)
|
|
|
+ {
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+ //第二步,点云抽稀,抽稀后的点云大约在8192左右,
|
|
|
+ // 如果有多辆车(多个yolo框),取第一个框
|
|
|
+ YoloBox yolo_box=boxes[0];
|
|
|
+ pcl::PointXYZ minp, maxp;
|
|
|
+ minp.x = yolo_box.x;
|
|
|
+ minp.y = yolo_box.y;
|
|
|
+ maxp.x = minp.x + yolo_box.w;
|
|
|
+ maxp.y = minp.y + yolo_box.h;
|
|
|
+
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_input_sift(new pcl::PointCloud<pcl::PointXYZ>());
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_downsample(new pcl::PointCloud<pcl::PointXYZ>());
|
|
|
+ /// ///体素网格 下采样
|
|
|
+ pcl::VoxelGrid<pcl::PointXYZ> vgfilter;
|
|
|
+ vgfilter.setInputCloud(cloud_in);
|
|
|
+ vgfilter.setLeafSize(60.f, 60.f, 50.f);
|
|
|
+ vgfilter.filter(*cloud_downsample);
|
|
|
+ //限制 x y
|
|
|
+ pcl::PassThrough<pcl::PointXYZ> passX;
|
|
|
+ pcl::PassThrough<pcl::PointXYZ> passY;
|
|
|
+ passX.setInputCloud(cloud_downsample);
|
|
|
+ passX.setFilterFieldName("x");
|
|
|
+ passX.setFilterLimits(minp.x, maxp.x);
|
|
|
+ passX.filter(*cloud_in);
|
|
|
+
|
|
|
+ passY.setInputCloud(cloud_in);
|
|
|
+ passY.setFilterFieldName("y");
|
|
|
+ passY.setFilterLimits(minp.y, maxp.y);
|
|
|
+ passY.filter(*cloud_in);
|
|
|
+
|
|
|
+ //第三步,分割车辆点云
|
|
|
+ std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> segmentation_clouds;
|
|
|
+ code=mp_point_sift->seg(cloud_in, segmentation_clouds, work_dir);
|
|
|
+ if(code!=SUCCESS)
|
|
|
+ {
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_car(new pcl::PointCloud<pcl::PointXYZ>);
|
|
|
+ pcl::copyPointCloud(*segmentation_clouds[1], *cloud_car);
|
|
|
+ cloud_targe=cloud_car;
|
|
|
+ return SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+ERROR_CODE Locater::locate_wheel_rotate_rect(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,cv::RotatedRect& rotate_rect,
|
|
|
+ std::string work_dir)
|
|
|
+{
|
|
|
+ if(cloud.get()==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"3dcnn input cloud uninit";
|
|
|
+ return LOCATER_3DCNN_INPUT_CLOUD_UNINIT;
|
|
|
+ }
|
|
|
+ if(cloud->size()==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"locate_3dcnn input cloud empty";
|
|
|
+ return LOCATER_3DCNN_INPUT_CLOUD_EMPTY;
|
|
|
+ }
|
|
|
+ if(mp_cnn3d==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"locate_wheel 3dcnn is not init";
|
|
|
+ return LOCATER_3DCNN_UNINIT;
|
|
|
+ }
|
|
|
+ //识别车轮
|
|
|
+ ERROR_CODE code;
|
|
|
+ code=mp_cnn3d->predict(cloud,rotate_rect,work_dir);
|
|
|
+ if(code!=SUCCESS)
|
|
|
+ {
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+ //根据plc限制判断合法性
|
|
|
+ if(rotate_rect.center.y>=930 || rotate_rect.center.y<=200)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<" Y is out of range by plc (200 , 900) Y:"<<rotate_rect.center.x;
|
|
|
+ return LOCATER_Y_OUT_RANGE_BY_PLC;
|
|
|
+ }
|
|
|
+ return SUCCESS;
|
|
|
+
|
|
|
|
|
|
- ///获取task中input点云
|
|
|
- pcl::PointCloud<pcl::PointXYZ>::Ptr t_cloud_input=task->get_locate_cloud();
|
|
|
- std::cout<<" execute locate task";
|
|
|
- usleep(1000*1000);
|
|
|
+}
|
|
|
|
|
|
+ERROR_CODE Locater::measure_height(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_car,float& height)
|
|
|
+{
|
|
|
+ if(cloud_car.get()==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"measure height input cloud uninit";
|
|
|
+ return LOCATER_MEASURE_HEIGHT_CLOUD_UNINIT;
|
|
|
+ }
|
|
|
+ if(cloud_car->size()==0)
|
|
|
+ {
|
|
|
+ return LOCATER_MEASURE_HEIGHT_CLOUD_EMPTY;
|
|
|
+ }
|
|
|
+ pcl::PointXYZ min_point,max_point;
|
|
|
+ pcl::getMinMax3D(*cloud_car,min_point,max_point);
|
|
|
+ //限制车高的范围,检验结果
|
|
|
+ height=max_point.z;
|
|
|
+ if(height<1000||height>2000)
|
|
|
+ {
|
|
|
+ return LOCATER_HEIGHT_OUT_RANGE;
|
|
|
+ }
|
|
|
return SUCCESS;
|
|
|
+}
|
|
|
|
|
|
+ERROR_CODE Locater::locate(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in,
|
|
|
+ Locate_information& locate_information, std::string work_dir)
|
|
|
+{
|
|
|
+ if(cloud_in.get()==0)
|
|
|
+ {
|
|
|
+ LOG(ERROR)<<"locate input cloud is not init";
|
|
|
+ return LOCATER_INPUT_CLOUD_UNINIT;
|
|
|
+ }
|
|
|
+ if(cloud_in->size()==0) {
|
|
|
+ LOG(ERROR)<<"input cloud is empty";
|
|
|
+ return LOCATER_INPUT_CLOUD_EMPTY;
|
|
|
+ }
|
|
|
+ //置初始结果为错误
|
|
|
+ locate_information.locate_correct=false;
|
|
|
+ ERROR_CODE code;
|
|
|
+ std::lock_guard<std::mutex> t_lock(m_mutex_lock);
|
|
|
+ //第一步 yolo定位车辆外接矩形
|
|
|
+ std::vector<YoloBox> t_yolo_boxes;
|
|
|
+ code=locate_yolo(cloud_in,t_yolo_boxes,work_dir);
|
|
|
+ if(SUCCESS!=code)
|
|
|
+ {
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+
|
|
|
+ //第二步 ,根据yolo框结合PointSift识别车身点云
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_car(new pcl::PointCloud<pcl::PointXYZ>);
|
|
|
+ code=locate_sift(cloud_in,t_yolo_boxes,cloud_car,work_dir);
|
|
|
+ if(code!=SUCCESS)
|
|
|
+ {
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+
|
|
|
+ //第三步,计算车辆高度
|
|
|
+ float height_car=0;
|
|
|
+ code=measure_height(cloud_car,height_car);
|
|
|
+ if(SUCCESS!=code)
|
|
|
+ {
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+
|
|
|
+ //第四步,识别轮胎,并根据轮胎数量计算旋转矩形
|
|
|
+ cv::RotatedRect rotate_rect;
|
|
|
+ code=locate_wheel_rotate_rect(cloud_car,rotate_rect,work_dir);
|
|
|
+ if(SUCCESS!=code)
|
|
|
+ {
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+
|
|
|
+ //第五步,根据rotate_rect计算长边与x轴的角度
|
|
|
+ const int C_PI=3.14159265;
|
|
|
+ cv::Point2f vec;
|
|
|
+ cv::Point2f vertice[4];
|
|
|
+ rotate_rect.points(vertice);
|
|
|
+ float len1 = pow(vertice[0].x - vertice[1].x, 2.0) + pow(vertice[0].y - vertice[1].y, 2.0);
|
|
|
+ float len2 = pow(vertice[1].x - vertice[2].x, 2.0) + pow(vertice[1].y - vertice[2].y, 2.0);
|
|
|
+ if (len1 > len2) {
|
|
|
+ vec.x = vertice[0].x - vertice[1].x;
|
|
|
+ vec.y = vertice[0].y - vertice[1].y;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ vec.x = vertice[1].x - vertice[2].x;
|
|
|
+ vec.y = vertice[1].y - vertice[2].y;
|
|
|
+ }
|
|
|
+ float angle_x = 180.0 / C_PI * acos(vec.x / sqrt(vec.x * vec.x + vec.y * vec.y));
|
|
|
+ //角度检验, 根据plc限制,角度应该在(80-100,260-280)
|
|
|
+ if( !((angle_x>80&&angle_x<100) || (angle_x>260&&angle_x<280)) )
|
|
|
+ {
|
|
|
+ return LOCATER_ANGLE_OUT_RANGE;
|
|
|
+ }
|
|
|
+
|
|
|
+ //第六步,结果赋值
|
|
|
+ //角度以度为单位
|
|
|
+ locate_information.locate_x=rotate_rect.center.x;
|
|
|
+ locate_information.locate_y=rotate_rect.center.y;
|
|
|
+ locate_information.locate_theta = angle_x;
|
|
|
+ locate_information.locate_length=std::max(rotate_rect.size.width,rotate_rect.size.height);
|
|
|
+ locate_information.locate_width=std::min(rotate_rect.size.width,rotate_rect.size.height);
|
|
|
+ locate_information.locate_hight=height_car;
|
|
|
+ locate_information.locate_wheel_base=std::max(rotate_rect.size.width,rotate_rect.size.height);
|
|
|
+ locate_information.locate_correct=true;
|
|
|
+ LOG(INFO) << "Locate SUCCESS :" << " center:" << "[" << locate_information.locate_x
|
|
|
+ << "," << locate_information.locate_y<< "] size= "
|
|
|
+ << locate_information.locate_length << ", "
|
|
|
+ << locate_information.locate_width << "," << locate_information.locate_hight
|
|
|
+ << " angle=" << locate_information.locate_theta ;
|
|
|
+
|
|
|
+ return SUCCESS;
|
|
|
}
|