Python实现RT-DETR的Tensorrt模型推理

'''
@Author  :***
@Date    :2023/10/29 13:29 
'''
import tensorrt as trt
import pycuda.driver as cuda
import pycuda.autoinit
import random
import os
import numpy as np
import cv2
import time


random.seed(3)
CLASS_COLORS = [[random.randint(0, 255) for _ in range(3)] for _ in range(80)]


class HostDeviceMem(object):
    def __init__(self, host_mem, device_mem):
        self.host = host_mem
        self.device = device_mem
    def __str__(self):
        return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device)
    def __repr__(self):
        return self.__str__()

def alloc_buf_N(engine,data):
    '''
    :brief:分配输入输出内存
    :param engine:读取后的模型
    :param data:待推理数据
    :return:
    '''
    inputs = []
    outputs = []
    bindings = []
    stream = cuda.Stream()
    data_type = []
    for ind,binding in enumerate(engine):
        if engine.binding_is_input(binding):
            size = data.shape[0]*data.shape[1]*data.shape[2]*data.shape[3]#待修改
            dtype = trt.nptype(engine.get_binding_dtype(binding))
            data_type.append(dtype)
            # Allocate memory on the host,在主机上分配内存
            host_mem = cuda.pagelocked_empty(size, dtype)
            # Allocate memory on the device,在显卡上分配内存
            device_mem = cuda.mem_alloc(host_mem.nbytes)
            # Append the device buffer to device bindings.将设备缓冲区附加到设备绑定
            bindings.append(int(device_mem))
            inputs.append(HostDeviceMem(host_mem, device_mem))
        else:
            #size = trt.volume(engine.get_binding_shape(binding)[1:]) * batch_size
            size = engine.get_binding_shape(4)[0]*6#待修改
            print(engine.get_binding_shape(4))
            #print(size,engine.max_batch_size,engine.get_binding_shape(binding)[1:],"---")
            host_mem = cuda.pagelocked_empty(size, data_type[0])
            device_mem = cuda.mem_alloc(host_mem.nbytes)
            bindings.append(int(device_mem))
            #print(bindings)
            outputs.append(HostDeviceMem(host_mem, device_mem))
            #print(outputs)
    return inputs, outputs, bindings, stream

def do_inference_v2(context, inputs, bindings, outputs, stream, data,batch_size):
    '''
    :brief:执行推理
    :param context: engine的context
    :param inputs: 输入,包括输入尺寸,reshape后的数据,缩放比例等
    :param bindings: alloc_buf_N函数返回的内容
    :param outputs: alloc_buf_N函数返回的内容
    :param stream: alloc_buf_N函数返回的内容
    :param data: 输入数据
    :param batch_size: 批次大小
    :return: 推理结果
    '''
    for inp in inputs:
        cuda.memcpy_htod_async(inp.device, inp.host, stream)
    # set batchsize,设置batchsize
    context.set_binding_shape(0, data.shape)
    # Run inference.执行推理
    context.execute_async(batch_size=batch_size, bindings=bindings, stream_handle=stream.handle)

    # Transfer predictions back from the GPU.从GPU发回预测
    for out in outputs:
        cuda.memcpy_dtoh_async(out.host, out.device, stream)

    # Writes the contents of the system buffers back to disk to ensure data synchronization.将系统缓冲区的内容写回磁盘以确保数据同步。
    stream.synchronize()

    # Return only the host outputs.仅返回主机输出
    return [out.host for out in outputs]

trt_logger = trt.Logger(trt.Logger.INFO)

def load_engine(engine_path):
    '''
    :brief:加载engine模型
    :param engine_path: engine模型路径
    :return: 读取后的对象
    '''
    TRT_LOGGER = trt.Logger(trt.Logger.ERROR)
    with open(engine_path, 'rb') as f, trt.Runtime(TRT_LOGGER) as runtime:
        return runtime.deserialize_cuda_engine(f.read())

def bbox_cxcywh_to_xyxy(x):
    '''
    :brief:未使用
    :param x:
    :return:
    '''
    bbox = np.zeros_like(x)
    bbox[...,:2] = x[...,:2] - 0.5 * x[...,2:]
    bbox[...,2:] = x[...,:2] + 0.5 * x[...,2:]
    return bbox

def getFileList(dir, Filelist, ext=None):
    '''
    :brief:获取文件夹及其子文件夹中文件列表
    :param dir: 文件夹根目录
    :param Filelist: 存储路径的列表,传入时为空
    :param ext: 文件扩展名,可不写
    :return: 返回Filelist
    '''
    newDir = dir
    if os.path.isfile(dir):
        if ext is None:
            Filelist.append(dir)
        else:
            if ext in dir[-3:]:
                Filelist.append(dir)

    elif os.path.isdir(dir):
        for s in os.listdir(dir):
            newDir = os.path.join(dir, s)
            getFileList(newDir, Filelist, ext)

    return Filelist

def result_devide_for_batch(output,batch_size):
    '''
    :brief:相当于reshape功能,将1*7200的数据返回成batchsize*300*6的形状
    :param output: 推理返回的结果
    :param batch_size: 批大小
    :return: reshape后的列表,3维
    '''
    res = []
    res_2 = []
    flag = len(output)/batch_size
    for i in range(0,batch_size):
        res.append(output[int(i*flag):int((i+1)*flag)])
    for j in range(0,len(res)):
        res_temp = []
        for z in range(0,int(len(res[j])/6)):
            res_temp.append(res[j][int(z*6):int((z+1)*6)])
        res_2.append(res_temp)
    return res_2

def deal_rect_for_img(list_2,labels_num,conf_thr):
    list_res = []
    list_label_id = []
    for i in range(0,len(list_2)):
        if len(list_res)==0:
            if list_2[i][0] not in list_label_id:
                if list_2[i][1] >= conf_thr:
                    list_res.append(list_2[i])
                    list_label_id.append(list_2[i][0])
        else:
            if len(list_res)<labels_num:
                if list_2[i][0] not in list_label_id:
                    if list_2[i][1]>=conf_thr:
                        list_res.append(list_2[i])
                        list_label_id.append(list_2[i][0])
            else:
                break
    return list_res

def img_loader(img_path, input_h, input_w, batch_size, img_format):
    '''
    :brief:按batch加载图像,形成模型输入所需要的维度
    :param img_path: 图像路径
    :param input_h: 模型输入的高
    :param input_w: 模型输入的宽
    :param batch_size: 批大小
    :param img_format: 图像类型,png or jpg
    :return: 按照批次返回图像路径列表,原图列表,归一化后的图像列表,图像shape列表,图像缩放比例列表
    '''
    res_img_path = []
    res_img_path_temp = []
    # res_img = []
    # res_img_temp = []
    # res_img_loader = []
    # res_img_loader_temp = []
    res_im_shape = []
    res_im_shape_temp = []
    res_scale_factor = []
    res_scale_factor_temp = []
    img_path_list = []
    img_path_list = getFileList(img_path, img_path_list, img_format)
    count = 1
    flag = len(img_path_list)%batch_size
    for src_path in img_path_list:
        img = cv2.imread(src_path)
        img_copy = img.copy()
        image_h, image_w = img.shape[:2]
        ratio_h = input_h / image_h
        ratio_w = input_w / image_w
        im_shape = np.array([float(input_h), float(input_w)]).astype('float32')#待修改
        scale_factor = np.array([float(ratio_h), float(ratio_w)]).astype('float32')
        img = cv2.resize(img, (0, 0), fx=ratio_w, fy=ratio_h, interpolation=2)
        img = img[:, :, ::-1] / 255.0
        img = img.transpose(2, 0, 1)
        if count%batch_size!=0:
            if flag!=0 and src_path==img_path_list[-1]:
                for i in range(0,batch_size-flag+1):
                    #res_img_loader_temp.append(img)
                    res_im_shape_temp.append(im_shape)
                    res_scale_factor_temp.append(scale_factor)
                    #res_img_temp.append(img_copy)
                    res_img_path_temp.append(src_path)

                #res_img_loader.append(np.array(res_img_loader_temp).astype("float32"))
                res_im_shape.append(np.array(res_im_shape_temp).astype("float32"))
                res_scale_factor.append(np.array(res_scale_factor_temp).astype("float32"))
                #res_img.append(np.array(res_img_temp).astype("float32"))
                res_img_path.append(res_img_path_temp)
            else:
                #res_img_loader_temp.append(img)
                res_im_shape_temp.append(im_shape)
                res_scale_factor_temp.append(scale_factor)
                #res_img_temp.append(img_copy)
                res_img_path_temp.append(src_path)
        else:
            #res_img_loader_temp.append(img)
            res_im_shape_temp.append(im_shape)
            res_scale_factor_temp.append(scale_factor)
            #res_img_temp.append(img_copy)
            res_img_path_temp.append(src_path)

            #res_img_loader.append(np.array(res_img_loader_temp).astype("float32"))
            res_im_shape.append(np.array(res_im_shape_temp).astype("float32"))
            res_scale_factor.append(np.array(res_scale_factor_temp).astype("float32"))
            #res_img.append(np.array(res_img_temp).astype("float32"))
            res_img_path.append(res_img_path_temp)

            #res_img_loader_temp = []
            res_im_shape_temp = []
            res_scale_factor_temp = []
            #res_img_temp = []
            res_img_path_temp = []
        count = count + 1
        #np.array(res_img_loader).astype("float32"),,np.array(res_img).astype("float32")
    return res_img_path,np.array(res_im_shape).astype("float32"),np.array(res_scale_factor).astype("float32")

def load_img_based_img_path(res_img_path_batch,input_h,input_w):
    res_img_loader = []
    res_img = []
    start = time.time()
    for i in range(0,len(res_img_path_batch)):
        img = cv2.imread(res_img_path_batch[i])
        img_copy = img.copy()
        image_h, image_w = img.shape[:2]
        ratio_h = input_h / image_h
        ratio_w = input_w / image_w
        img = cv2.resize(img, (0, 0), fx=ratio_w, fy=ratio_h, interpolation=2)
        img = img[:, :, ::-1] / 255.0
        img = img.transpose(2, 0, 1)
        res_img_loader.append(img)
        res_img.append(img_copy)
    end = time.time()
    print("加载图像:",end-start)
    return np.array(res_img_loader).astype("float32"),np.array(res_img).astype("float32")#待修改


def infer(engine_path,img_path,out_path,num_rect,range_list,conf_thr,CLASS_NAMES,img_format="png"):
    '''
    :brief:预标注函数
    :param engine_path: 预标注engine模型路径
    :param img_path: 待标注图像路径
    :param xml_path: 生成的标注文件存放路径
    :param num_rect: 每张图最多绘制num_rect个框
    :param conf_thr: 低于conf_thr不画框
    :param CLASS_NAMES: 标注类别
    :param img_format:
    :return: 图像类型,png or jpg
    '''
    # if not os.path.exists(engine_path.replace(engine_path.split("\\")[-1].split(".e")[0],engine_path.split("\\")[-1].split(".e")[0] + "_1")):
    #     model_decoder(engine_path)
    # engine_path = engine_path.replace(engine_path.split("\\")[-1].split(".e")[0],engine_path.split("\\")[-1].split(".e")[0] + "_1")
    engine = load_engine(engine_path)
    #os.remove(engine_path)
    context = engine.create_execution_context()
    channel,batch_size,input_h,input_w = engine.get_binding_shape(1)[1],engine.get_binding_shape(1)[0],engine.get_binding_shape(1)[2],engine.get_binding_shape(1)[3]
    print(batch_size,input_h,input_w)
    # res_img_loader,res_img,
    print("数据加载中,请稍后")
    res_img_path,res_im_shape, res_scale_factor = img_loader(img_path,input_h,input_w,batch_size,img_format)
    print("数据加载完成,开始推理")
    for i in range(0,len(res_img_path)):
        res_img_loader ,res_img = load_img_based_img_path(res_img_path[i],input_h,input_w)
        res_img_loader = np.ascontiguousarray(res_img_loader, dtype=np.float32)
        inputs_alloc_buf, outputs_alloc_buf, bindings_alloc_buf, stream_alloc_buf = alloc_buf_N(engine, res_img_loader)
        inputs_alloc_buf[0].host = res_im_shape[i]
        inputs_alloc_buf[1].host = res_img_loader.reshape(-1)
        inputs_alloc_buf[2].host = res_scale_factor[i]
        start = time.time()
        net_output = do_inference_v2(context, inputs_alloc_buf, bindings_alloc_buf, outputs_alloc_buf, stream_alloc_buf,res_img_loader,batch_size)
        end = time.time()
        print("推理耗时:",end-start)
        print("----------------------------------------------------------------- ----------------------------------------")
        res = result_devide_for_batch(net_output[1],batch_size)
        for e in range(0,len(res)):
            res_cut = deal_rect_for_img(res[e],len(CLASS_NAMES),conf_thr)
            src_img = res_img[e].copy()

            for r in range(0,num_rect):
                if res[e][r][1]<conf_thr:
                    print(res[e][r][1], res_img_path[i][e])
                    continue
                x1, y1, x2, y2, label_id = int(res[e][r][2]), int(res[e][r][3]), int(res[e][r][4]), int(res[e][r][5]), int(res[e][r][0])
                label = CLASS_NAMES[int(label_id)]
                red,green,blue = random.randint(64,192),random.randint(64,192),random.randint(64,192)
                cv2.rectangle(res_img[e], (x1, y1), (x2, y2), (red, green, blue), 2)
                x_change = x1 - random.randint(1,10) if x1 - random.randint(1,10)>0 else x1
                y_change = y1 - random.randint(1,10) if y1 - random.randint(1,10)>0 else y1
                cv2.putText(res_img[e], str(label) + ": " + str(res[e][r][1])[0:4], (x_change, y_change),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (red, green, blue), 1)
            if len(res_cut)==0:
                no_labels = os.path.join(out_path,"no_labels")
                if not os.path.isdir(no_labels):
                    os.mkdir(no_labels)
                #cv2.imwrite(os.path.join(no_labels, res_img_path[i][e].split("\\")[-1]), src_img)
            for z in range(0,len(res_cut)):
                new_dir = os.path.join(out_path,CLASS_NAMES[int(res_cut[z][0])])
                if not os.path.isdir(new_dir):
                    os.mkdir(new_dir)
                new_dir = os.path.join(new_dir,range_list[int(10*res_cut[z][1])])
                if not os.path.isdir(new_dir):
                    os.mkdir(new_dir)
                # if flag_jl == True or flag_hd==True:
                #     cv2.imwrite(os.path.join(new_dir,res_img_path[i][e].split("\\")[-1].split(".pn")[0] + "_res.png"), res_img[e])
                #     cv2.imwrite(os.path.join(new_dir, res_img_path[i][e].split("\\")[-1]),src_img)
                cv2.imwrite(os.path.join(new_dir, res_img_path[i][e].split("\\")[-1].split(".pn")[0] + "_res.png"),res_img[e])
                #cv2.imwrite(os.path.join(new_dir, res_img_path[i][e].split("\\")[-1]), src_img)

def auto_label():
    CLASS_NAMES = ["class1","class2","class3"]
    range_list = ["0.0-0.1","0.1-0.2","0.2-0.3","0.3-0.4","0.4-0.5","0.5-0.6","0.6-0.7","0.7-0.8","0.8-0.9","0.9-1.0"]
    img_format = "jpg"
    conf_thr = 0.01 #阈值以下不存
    max_num_each_img = 30 #最多画几个框
    img_path = r"C:\Users\***\Desktop\test_pic_2" #待推理图像路径
    out_path = r"C:\Users\***\Desktop\test_pic_out" #输出路径
    #engine模型路径
    engine_path = r"./best_model.engine"
    if not os.path.exists(engine_path):
        print("模型路径不存在,请检查后重试")
        return
    if not os.path.isdir(img_path):
        print("图像路径不存在,请检查后重试")
        return
    infer(engine_path, img_path, out_path,max_num_each_img, range_list,conf_thr, CLASS_NAMES, img_format)


if __name__ == '__main__':
    auto_label()

代码存在重复读取数据的问题,推理速度被降低了一些,但整体不影响代码功能

代码还存在很多待优化的地方,欢迎大家提出自己的建议

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值