@startuml
title 摆扫测量模块类图

class Task_Base
{
    +~Task_Base();
    +virtual Error_manager init();//初始化任务单,初始任务单类型为 UNKONW_TASK
    +Error_manager update_statu(Task_statu task_statu,std::string statu_information="");//更新任务单
    +Task_type   get_task_type();//获取任务类型
    +Task_statu  get_statu();//获取任务单状态
    +std::string get_statu_information();//获取状态说明
}


class Locate_task
{
    +Locate_task();
    +~Locate_task();
    //设置测量输入点云()
    +Error_manager set_locate_cloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud);
    //获取输入点云()
    +pcl::PointCloud<pcl::PointXYZ>::Ptr get_locate_cloud();
    //获取测量结果()
    +Locate_information get_locate_information();
    //设置测量结果()
    +Error_manager set_locate_information(Locate_information information);
    //获取文件存放路径()
    +std::string get_save_path();
    //设置文件村昂路径()
    +Error_manager set_save_path(std::string path);

    -pcl::PointCloud<pcl::PointXYZ>::Ptr         m_locate_cloud_ptr;//测量算法输入点云
    -Locate_information                          m_locate_information;//测量结果存放结构体
    -std::string                                 m_save_path;//测量中间文件存放路径
}



class Detector 
{
    std::shared_ptr<void> detector_gpu_ptr;//yolo测量网络指针
    std::deque<std::vector<bbox_t>> prev_bbox_vec_deque;
    const int cur_gpu_id;
    float nms = .4;
    bool wait_stream;

    + Detector(std::string cfg_filename, std::string weight_filename, int gpu_id = 0);
    + ~Detector();

    + std::vector<bbox_t> detect(std::string image_filename, float thresh = 0.2, bool use_mean = false);
    + std::vector<bbox_t> detect(image_t img, float thresh = 0.2, bool use_mean = false);
    + image_t load_image(std::string image_filename);
    + void free_image(image_t m);
    + int get_net_width() const;
    + int get_net_height() const;
    + int get_net_color_depth() const;

    + std::vector<bbox_t> tracking_id(std::vector<bbox_t> cur_bbox_vec, bool const change_history = true,
                                                int const frames_story = 5, int const max_dist = 40);

    + void *get_cuda_context();

    //+ bool send_json_http(std::vector<bbox_t> cur_bbox_vec, std::vector<std::string> obj_names, int frame_id,
    //    std::string filename = std::string(), int timeout = 400000, int port = 8070);
    //重置图像大小,并识别()
    +std::vector<bbox_t> detect_resized(image_t img, int init_w, int init_h, float thresh = 0.2, bool use_mean = false);
    
}

class YoloDetector
{
	+YoloDetector(std::string cfg,std::string weights,float minx,float maxx,float miny,float maxy,float freq);
	+//设置输入点云的边界,识别的时候根据边界投影到图像()
	+//输入边界的长款比必须是1:1,否则会出现图像扭曲()
	+//freq:表示多长一个像素点()
    +Error_manager set_region(float minx, float maxx, float miny, float maxy,float freq);
	+virtual ~YoloDetector();
    +//识别函数, 将点云数据转换成图像格式保存,该函数已经过期(第一版算法,点云由两个雷达扫描)
    +//l:左边雷达扫描数据; r:右边雷达扫描数据()
    +//save_dir:中间数据保存路径()
	+Error_manager detect(cv::Mat& l, cv::Mat& r, std::vector<YoloBox>& boxes,std::string save_dir);
	+//将点云投影成图像, 识别车辆外接矩形框()
	+Error_manager detect(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in, std::vector<YoloBox>& boxes, std::string save_dir);

    -//释放图像内存()
    -void free_img(image_t img);
    -//opencv图像类型转换成 image_t 格式,并调整大小()
    -std::shared_ptr<image_t> mat_to_image_resize(cv::Mat mat) const
    -static std::shared_ptr<image_t> mat_to_image(cv::Mat img_src)
    -static image_t ipl_to_image(IplImage* src)
    -static image_t make_empty_image(int w, int h, int c)
    -static image_t make_image_custom(int w, int h, int c)
	-Detector*	m_pDetector;
	-float m_minx;
	-float m_maxx;
	-float m_miny;
	-float m_maxy;
	-float m_freq;
}

class PointSifter
{
    +//初始化PointSift()
    +//point_num:pointsift输入点数()
    +//cls_num:PointSift输出类别数()
	+PointSifter(int point_num, int cls_num);
	+~PointSifter();
	+//加载网络参数()
	+//meta:tensorflow网络结构定义文件()
	+//cpkt:tensorflow网络权重()
	+bool Load(std::string meta, std::string cpkt);
	+//预测()
	+//data:输入数据,大小为  输入点数*3()
	+//output:输出数据,大小为  输入点数*类别数()
	+bool Predict(float* data, float* output);
	+//错误原因()
	+std::string LastError();

	-PointSifter();
	-std::mutex		m_mutex;
	-std::string		m_error;
	-bool			m_bInit;
	-int				m_point_num;
	-int				m_cls_num;
	-void*			m_sess;
}
note right of PointSifter
    sift识别类,导入类
    负责pointsift网络的加载识别,
    内部加锁,保证只有一个识别任务占有
end note


class Point_sift_segmentation 
{
	+Point_sift_segmentation(int point_size,int cls,float freq,pcl::PointXYZ minp,pcl::PointXYZ maxp);
    +//设置要识别的点云区域()
    +Error_manager set_region(pcl::PointXYZ minp, pcl::PointXYZ maxp);
    +//初始化网络, 加载网络权重()
	+virtual Error_manager init(std::string graph,std::string cpkt);
	+//分割函数,输入点云,输出各类的点云,并保存中间文件方便查看识别结果()
	+//cloud:输入点云()
	+//clouds:输出分类好的多个点云(附带颜色,红色为杂物,绿色为车,白色为地面)
	+virtual Error_manager seg(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
	+    std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr>& clouds, std::string save_dir);
	+virtual ~Point_sift_segmentation();

    -//将点云数据转换到float*()
    -//cloud:输入点云()
    -//output:转换结果保存地址,函数内不负责内存的分配与释放()
	-bool	Create_data(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, float* output);
    -//将float*转换成点云()
    -//output:点云对应的类别,大小为  点数*类别()
    -//cloud:点云数据(xyz)()
    -//cloud_seg::输入带颜色的点云()
	-bool    RecoveryCloud(float* output, float* cloud, std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr>& cloud_seg);
	-bool	FilterObs(std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr>& cloud_seg, std::string save_dir);

	-float		        m_freq;
    -pcl::PointXYZ		m_minp;
    -pcl::PointXYZ		m_maxp;

}
note bottom of Point_sift_segmentation
 * 封装PointSift点云分割网络,输入点云,分割出汽车,检验结果
 * 功能包括将pcl点云数据格式转换成原始数据格式float*
 * 将识别数据转换成点云数据并用不同颜色区分
end note


class LocateParameter
{
    +获取各个配置参数()
    +序列化配置到文件()
    +从文件流读取配置()
}
note left of LocateParameter
    测量算法参数配置类
    格式protobuf,
    详见locater_parameter.proto文件
end note

class Locater
{
    +ocater();
    +Locater();

    +/初始化测量算法参数()
    +Error_manager init(Measure::LocateParameter parameter);

    +/获取测量模块状态(错误码);返回是否能执行任务,以及不能执行任务的原因()
    +Error_manager get_error();

    +//执行任务,()
    +//task:测量任务()
    +//time_out:超时时间,单位秒()
    +Error_manager execute_task(Task_Base* task,double time_out=5);

    -//测量算法函数()
    -//cloud_in:输入点云()
    -//locate_information:测量结果()
    -//work_dir:中间文件保存路径()
    -Error_manager locate(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in,

    -Locate_information& locate_information, std::string work_dir);

    -//yolo定位车辆外接矩形()
    -//cloud_in:输入点云,定位算法内部不会修改点云内容()
    -//boxes:定位到的外接box框()
    -//work_dir:中间文件输出路径()
    -Error_manager locate_yolo(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in,
    -    std::vector<YoloBox>& boxes, std::string work_dir);

    -//根据yolo识别结果, 利用PointSift从场景中分割车辆点云()
    -//cloud:输入点云()
    -//boxes:yolo识别结果()
    -//cloud_target:车辆点云()
    -//work_dir:中间文件保存路径()
    -Error_manager locate_sift(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, std::vector<YoloBox> boxes,
    -                       pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_wheel,pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_car,
    -                       std::string work_dir);

    -//输入汽车点云,识别轮胎,并计算轴长,宽,中心,旋转角()
    -Error_manager locate_wheel(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,float& center_x,float& center_y,float& wheel_base,float& width,float& angle,std::string work_dir);
    
    -//根据汽车点云计算车高()
    -//cloud_car:车辆点云()
    -Error_manager measure_height(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_car,float& height);
    
    -// 保存点云成txt到文件()
    -static void save_cloud_txt(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,std::string save_file);

    -Measure::LocateParameter           m_locate_parameter;
    -Point_sift_segmentation*                mp_point_sift;
    -YoloDetector*                           mp_yolo_detector;
    -Cnn3d_segmentation*                     mp_cnn3d;

    -std::mutex						        m_mutex_lock;
}


Locate_task --|> Task_Base
YoloDetector --> Detector
Point_sift_segmentation --|> PointSifter

Locater --> Point_sift_segmentation
Locater --> YoloDetector
Locater --> LocateParameter



@enduml