python调用c++深度学习模型生成的dll(传入图片,返回多个结果)

 这里主要通过python调用c++深度学习模型,传入图片,c++处理,并返回结果,python接收结果,这个过程的接口如何设计转换。

python端代码接口


# 定义dll返回的结果类型,这里应该和c++中定义的返回结构体一一对应
class Result_process(Structure):
    _fields_ = [
        ('count', c_int),
        ('ID', c_int),
        ('score',c_float),
        ('x', c_float),
        ('y', c_float),
        ('width',c_float),
        ('height',c_float),
    ]

# 这里初始化模型参数,需要向c++的dll传入字符串即模型的路径,字符串必须转换为字节类型的才能传入
class model:
    def __init__(self, engineFile_path, onnx_path):
        self.engineFile_path = engineFile_path
        self.onnx_path = onnx_path
           
    def init(self):
        # 初始化,加载模型,可以不用加b
        dll= ctypes.cdll.LoadLibrary('.//src//model_c++.dll')  
        # 字符串需要加b,针对可变字符串必须使用ctypes.create_string_buffer进行转换,否则报错
        #path = b"D://VScode_prj//tkjc//src//model.onnx"
        chr1=ctypes.create_string_buffer(self.onnx_path)
        #chr1=ctypes.create_string_buffer(path)
        # 把转换后的字符串进行初始化,这里的初始化就是加载模型,传入模型的字符串
        ret = dll.Init(chr1)
        if ret == -1:
            print("-----模型初始化失败--------")
            return ret
        # 这里把dll的推理函数拿出
        self.process = dll.process
        # 声明输入的数据类型
        self.process.argtypes=[c_char_p,c_int,c_int,c_int]
        # 声明返回结果的类型
        self.process.restype = POINTER(Result_process * 1000)

    def infer(self, src):
        if src is None:
            print("----图片为空----")
            return -1
        cols = src.shape[1]
        rows = src.shape[0]
        channels = 0
        if 3==len(src.shape):
            channels = 3	
        # 这里是把图片数据转换为dll可识别的类型
        src = np.asarray(src, dtype=np.uint8) 
        # 这里就获取图片数据的指针
        src1 = src.ctypes.data_as(c_char_p)
        # 传入图片数据,因为只有指针不行,因此需要图片的宽高和通道数,dll才能准换为c++可处理的数据,c++拿到图片后处理并返回结果
        struct_res = self.process(src1, rows, cols, channels)
        data = dict()
        #print("------开始获取数据--------")
        for i in range(struct_res.contents[0].count):
            ID=struct_res.contents[i].ID
            score=struct_res.contents[i].score
            x=struct_res.contents[i].x
            y=struct_res.contents[i].y
            width=struct_res.contents[i].width
            height=struct_res.contents[i].height
            #print("ID:{}, score:{}, x:{}, y:{}, width:{}, height:{}".format(ID, score, x, y, width, height))
            data[ID] = [score, x, y, width, height]
        return data

c++端接口设计

接口设计:

//这里是返回结果定义的结构体,和python端口定义的是一一对应的
typedef struct 
{
	int count = 0; //当前帧的目标个数
	int ID = 0;//当前目标的ID
	float score = 0;//当前目标的评分
	//cv::Rect_<float> box_tlbr;//目标的左上角和右下角坐标,这里考虑使用python调用,使用简单数据类型
	float x = 0.0;
	float y = 0.0;
	float width = 0.0;
	float height = 0.0;
}SingleObjectResult;

/
//整体需要转换为c类型,因为python只支持c类型的代码和参数
extern "C" {
	//c++的版本的深度学习模型应该是一个类,如果不知道深度学习如何使用类操作,建议看看yolov5的c++版本实现
	//定义一个模型类的变量
	Model tracks;
	//这里是初始化接口函数,python调用的初始化函数就是来源这里
	extern "C" _declspec(dllexport) int Init(char* onnx_path)
	{
		printf("-----开始初始化-----");
		string str1;
		str1 = onnx_path;
		std::cout << str1.c_str() << endl;
		return tracks.Init(str1.c_str());
	}
	//这里推理函数,python调用的推理函数也是来源这里
	//传入的是uchar类型的指针,该指针就是指向python传入的图片数据
	extern "C" _declspec(dllexport) SingleObjectResult* process(uchar * frame_data, int height, int width, int channels)
	{
		//printf("-----开始检测-----");
		/*string str2;
		str2 = video_path;
		std::cout << str2.c_str() << endl;*/
		return tracks.processs(frame_data, height, width, channels);
	}
}

一些关键函数:

//解析从python传送过来图片数据,先把内存的图片数据转换为opencv类型的数据,共后面的处理
//这里处理方法很多,但是建议使用opencv提供的构造函数直接转换,这样效率高
Mat Model::readfrombuffer(uchar* frame_data, int height, int width, int channels) 
{
	//Mat img(height, width, CV_8UC3);
	Mat img = Mat(height, width, CV_8UC3, frame_data);
	return img;
}

c++主要函数实现

//初始化类函数,主要初始化模型的加载
int Model::Init(const std::string& onnx_path) {
	//这里替换你自己的初始化程序即可
	detconfig.model_file = onnx_path;//true
	det = DetectorFactory::create_object(detconfig);
	if (!det->init())
	{
		std::cout << "\n模型初始化失败,请检查传入模型的路径: " << onnx_path << endl;
		return -1;
	}

	config.conf_thres = 0.4f;
	config.K = 500;
	config.track_buffer = 30;

	std::cout << "模型加载成功,初始化完成" << std::endl;
	return 1;
}

//推理函数
SingleObjectResult* Model::processs(uchar* frame_data, int height, int width, int channels)
{
	//定义一个返回结构体,这里为了避免系统自动释放内存,因此申请内存
	SingleObjectResult* Result = new SingleObjectResult[1000];
	Mat frame = readfrombuffer(frame_data, height, width, channels);
	if (frame.empty())
	{
		std::cout << "-----该帧出错,视频有问题-----" << std::endl;
		return Result;
	}
	det->get_detection(frame, vec_db, vec_features);
	std::vector<std::shared_ptr<STrack>> tracks = jde->update(vec_db, vec_features);

	//提取跟踪信息
	int count = tracks.size();
	int index = 0;
	for (auto& tr : tracks)
	{
		//检测框
		//cv::Rect_<float> loc = tr->to_tlwh_rect();
		DETECTBOX ret = tr->to_tlwh_box();
		//检测ID
		int ID = tr->track_id;
		//检测得分
		float score = tr->score;
		//当前帧号
		int frame_id = tr->frame_id;
		Result[index].count = count;
		Result[index].ID = ID;
		Result[index].score = score;
		Result[index].x = ret[0];
		Result[index].y = ret[1];
		Result[index].width = ret[2];
		Result[index].height = ret[3];

		index += 1;
	}

	return Result;
}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值