#ifndef YOLO_DETECTOR__HH
#define YOLO_DETECTOR__HH

#include "opencv/highgui.h"
#include "opencv2/opencv.hpp"
#include <pcl/point_types.h>
#include <pcl/common/common.h>
#include "yolo_v2_class.hpp"
#include "../error_code/error_code.h"

#define YOLO_API_USED	1

typedef struct YOLO_BOX
{
    float x, y, w, h;
}YoloBox;

/*
 * yolo v2网络识别类, 输入图像大小为416*416.
 */
class YoloDetector
{
public:
	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);
protected:
    //释放图像内存
    void free_img(image_t img);
    //opencv图像类型转换成 image_t 格式,并调整大小
    std::shared_ptr<image_t> mat_to_image_resize(cv::Mat mat) const
    {
        if (mat.data == NULL) return std::shared_ptr<image_t>(NULL);
        cv::Mat det_mat;
        cv::resize(mat, det_mat, cv::Size(m_pDetector->get_net_width(), m_pDetector->get_net_height()));
        return mat_to_image(det_mat);
    }

    static std::shared_ptr<image_t> mat_to_image(cv::Mat img_src)
    {
        cv::Mat img;
        cv::cvtColor(img_src, img, cv::COLOR_RGB2BGR);
        std::shared_ptr<image_t> image_ptr(new image_t, [](image_t *img) { if(img->data) free(img->data); delete img; });
        std::shared_ptr<IplImage> ipl_small = std::make_shared<IplImage>(img);
        *image_ptr = ipl_to_image(ipl_small.get());
        return image_ptr;
    }
    static image_t ipl_to_image(IplImage* src)
    {
        unsigned char *data = (unsigned char *)src->imageData;
        int h = src->height;
        int w = src->width;
        int c = src->nChannels;
        int step = src->widthStep;
        image_t out = make_image_custom(w, h, c);
        int count = 0;

        for (int k = 0; k < c; ++k) {
            for (int i = 0; i < h; ++i) {
                int i_step = i*step;
                for (int j = 0; j < w; ++j) {
                    out.data[count++] = data[i_step + j*c + k] / 255.;
                }
            }
        }

        return out;
    }

    static image_t make_empty_image(int w, int h, int c)
    {
        image_t out;
        out.data = 0;
        out.h = h;
        out.w = w;
        out.c = c;
        return out;
    }

    static image_t make_image_custom(int w, int h, int c)
    {
        image_t out = make_empty_image(w, h, c);
        out.data = (float *)calloc(h*w*c, sizeof(float));
        return out;
    }

protected:
	Detector*	m_pDetector;
	float m_minx;
	float m_maxx;
	float m_miny;
	float m_maxy;
	float m_freq;
};
#endif

