首页 > 编程语言 >YOLOV5 onnx推理 python

YOLOV5 onnx推理 python

时间:2024-09-14 13:51:32浏览次数:8  
标签:YOLOV5 name img python onnx self shape new

 

 pip install onnx coremltools onnx-simplifier

 

3.使用onnx-simplier简化模型

python -m onnxsim best.onnx best-sim.onnx

 

# coding=utf-8
import cv2
import numpy as np
import onnxruntime
import torch
import torchvision
import time
import random
from utils.general import non_max_suppression
class YOLOV5_ONNX(object):
    def __init__(self,onnx_path):
        '''初始化onnx'''
        self.onnx_session=onnxruntime.InferenceSession(onnx_path)
        print(onnxruntime.get_device())
        self.input_name=self.get_input_name()
        self.output_name=self.get_output_name()
        self.classes=['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
        'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
        'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
        'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
        'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
        'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
        'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
        'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
        'hair drier', 'toothbrush']
    def get_input_name(self):
        '''获取输入节点名称'''
        input_name=[]
        for node in self.onnx_session.get_inputs():
            input_name.append(node.name)

        return input_name


    def get_output_name(self):
        '''获取输出节点名称'''
        output_name=[]
        for node in self.onnx_session.get_outputs():
            output_name.append(node.name)

        return output_name

    def get_input_feed(self,image_tensor):
        '''获取输入tensor'''
        input_feed={}
        for name in self.input_name:
            input_feed[name]=image_tensor

        return input_feed

    def letterbox(self,img, new_shape=(640, 640), color=(114, 114, 114), auto=False, scaleFill=False, scaleup=True,
                  stride=32):
        '''图片归一化'''
        # Resize and pad image while meeting stride-multiple constraints
        shape = img.shape[:2]  # current shape [height, width]
        if isinstance(new_shape, int):
            new_shape = (new_shape, new_shape)

        # Scale ratio (new / old)
        r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
        if not scaleup:  # only scale down, do not scale up (for better test mAP)
            r = min(r, 1.0)

        # Compute padding
        ratio = r, r  # width, height ratios

        new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
        dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  # wh padding

        if auto:  # minimum rectangle
            dw, dh = np.mod(dw, stride), np.mod(dh, stride)  # wh padding
        elif scaleFill:  # stretch
            dw, dh = 0.0, 0.0
            new_unpad = (new_shape[1], new_shape[0])
            ratio = new_shape[1] / shape[1], new_shape[0] / shape[0]  # width, height ratios

        dw /= 2  # divide padding into 2 sides
        dh /= 2

        if shape[::-1] != new_unpad:  # resize
            img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)

        top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
        left, right = int(round(dw - 0.1)), int(round(dw + 0.1))

        img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add border
        return img, ratio, (dw, dh)

    def xywh2xyxy(self,x):
        # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right
        y = np.copy(x)

        y[:, 0] = x[:, 0] - x[:, 2] / 2  # top left x
        y[:, 1] = x[:, 1] - x[:, 3] / 2  # top left y
        y[:, 2] = x[:, 0] + x[:, 2] / 2  # bottom right x
        y[:, 3] = x[:, 1] + x[:, 3] / 2  # bottom right y

        return y

    def nms(self,prediction, conf_thres=0.1, iou_thres=0.6, agnostic=False):
        if prediction.dtype is torch.float16:
            prediction = prediction.float()  # to FP32
        xc = prediction[..., 4] > conf_thres  # candidates
        min_wh, max_wh = 2, 4096  # (pixels) minimum and maximum box width and height
        max_det = 300  # maximum number of detections per image
        output = [None] * prediction.shape[0]
        for xi, x in enumerate(prediction):  # image index, image inference
            x = x[xc[xi]]  # confidence
            if not x.shape[0]:
                continue

            x[:, 5:] *= x[:, 4:5]  # conf = obj_conf * cls_conf
            box = self.xywh2xyxy(x[:, :4])

            conf, j = x[:, 5:].max(1, keepdim=True)
            x = torch.cat((torch.tensor(box), conf, j.float()), 1)[conf.view(-1) > conf_thres]
            n = x.shape[0]  # number of boxes
            if not n:
                continue
            c = x[:, 5:6] * (0 if agnostic else max_wh)  # classes
            boxes, scores = x[:, :4] + c, x[:, 4]  # boxes (offset by class), scores
            i = torchvision.ops.boxes.nms(boxes, scores, iou_thres)
            if i.shape[0] > max_det:  # limit detections
                i = i[:max_det]
            output[xi] = x[i]

        return output

    def clip_coords(self,boxes, img_shape):
        '''查看是否越界'''
        # Clip bounding xyxy bounding boxes to image shape (height, width)
        boxes[:, 0].clamp_(0, img_shape[1])  # x1
        boxes[:, 1].clamp_(0, img_shape[0])  # y1
        boxes[:, 2].clamp_(0, img_shape[1])  # x2
        boxes[:, 3].clamp_(0, img_shape[0])  # y2

    def scale_coords(self,img1_shape, coords, img0_shape, ratio_pad=None):
        '''
        坐标对应到原始图像上,反操作:减去pad,除以最小缩放比例
        :param img1_shape: 输入尺寸
        :param coords: 输入坐标
        :param img0_shape: 映射的尺寸
        :param ratio_pad:
        :return:
        '''

        # Rescale coords (xyxy) from img1_shape to img0_shape
        if ratio_pad is None:  # calculate from img0_shape
            gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1])  # gain  = old / new,计算缩放比率
            pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (
                        img1_shape[0] - img0_shape[0] * gain) / 2  # wh padding ,计算扩充的尺寸
        else:
            gain = ratio_pad[0][0]
            pad = ratio_pad[1]

        coords[:, [0, 2]] -= pad[0]  # x padding,减去x方向上的扩充
        coords[:, [1, 3]] -= pad[1]  # y padding,减去y方向上的扩充
        coords[:, :4] /= gain  # 将box坐标对应到原始图像上
        self.clip_coords(coords, img0_shape)  # 边界检查
        return coords

    def sigmoid(self,x):
        return 1 / (1 + np.exp(-x))



    def infer(self,img_path):
        '''执行前向操作预测输出'''
        # 超参数设置
        img_size=(640,640) #图片缩放大小
        # 读取图片
        src_img=cv2.imread(img_path)
        start=time.time()
        src_size=src_img.shape[:2]

        # 图片填充并归一化
        img=self.letterbox(src_img,img_size,stride=32)[0]

        # Convert
        img = img[:, :, ::-1].transpose(2, 0, 1)  # BGR to RGB, to 3x416x416
        img = np.ascontiguousarray(img)


        # 归一化
        img=img.astype(dtype=np.float32)
        img/=255.0

        # # BGR to RGB
        # img = img[:, :, ::-1].transpose(2, 0, 1)
        # img = np.ascontiguousarray(img)

        # 维度扩张
        img=np.expand_dims(img,axis=0)
        print('img resuming: ',time.time()-start)
        # 前向推理
        # start=time.time()
        input_feed=self.get_input_feed(img)
        # ort_inputs = {self.onnx_session.get_inputs()[0].name: input_feed[None].numpy()}
        pred = torch.tensor(self.onnx_session.run(None, input_feed)[0])
        results = non_max_suppression(pred, 0.5,0.5)
        print('onnx resuming: ',time.time()-start)
        # pred=self.onnx_session.run(output_names=self.output_name,input_feed=input_feed)



        #映射到原始图像
        img_shape=img.shape[2:]
        # print(img_size)
        for det in results:  # detections per image
            if det is not None and len(det):
                det[:, :4] = self.scale_coords(img_shape, det[:, :4],src_size).round()
        print(time.time()-start)
        if det is not None and len(det):
            self.draw(src_img, det)




    def plot_one_box(self,x, img, color=None, label=None, line_thickness=None):
        # Plots one bounding box on image img
        tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1  # line/font thickness
        color = color or [random.randint(0, 255) for _ in range(3)]
        c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
        cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)
        if label:
            tf = max(tl - 1, 1)  # font thickness
            t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]
            c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
            cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA)  # filled
            cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)

    def draw(self,img, boxinfo):
        colors = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(self.classes))]
        for *xyxy, conf, cls in boxinfo:
            label = '%s %.2f' % (self.classes[int(cls)], conf)
            # print('xyxy: ', xyxy)
            self.plot_one_box(xyxy, img, label=label, color=colors[int(cls)], line_thickness=1)

        cv2.namedWindow("dst",0)
        cv2.imshow("dst", img)
        cv2.imwrite("res1.jpg",img)
        cv2.waitKey(0)
        # cv2.imencode('.jpg', img)[1].tofile(os.path.join(dst, id + ".jpg"))
        return 0


if __name__=="__main__":
    model=YOLOV5_ONNX(onnx_path='./yolov5s6.onnx')
    model.infer(img_path="./data/images/bus.jpg")

 

 

结果显示:

 

标签:YOLOV5,name,img,python,onnx,self,shape,new
From: https://www.cnblogs.com/tangjunjun/p/16573327.html

相关文章

  • 爬虫代码 python
       importrequestsimporturllibimportosimporttimeprint('欢迎使用Aking爬虫图片下载器!')time.sleep(0.5)print('欢迎使用Aking爬虫图片下载器!!')time.sleep(0.5)print('欢迎使用Aking爬虫图片下载器!!!')time.sleep(0.5)print('准备就绪!')time.sle......
  • python爬虫连载20
    XPath语法:表达式描述nodename选取此节点的所有子节点/从根节点选取//选择任意位置的某个节点.选取当前节点..选取当前节点的父节点@选取属性    <?xmlversion="1.0"encoding="IS0-8859-1"?><classroom>      <student>             <id>1001</id>   ......
  • Python如何定义一个函数?
    在Python中,函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码块,它可以提高应用的模块性,和代码的重复利用率。那么Python如何定义一个函数?以下是具体内容介绍。在Python中定义函数有多种方法。最常见的方法是使用def关键字,后跟函数名称和一对圆括号。语法:......
  • Python语言如何编写函数?
    Python函数是指组织好的、可重复使用的、用来实现单一或相关联功能的代码段。Python函数包含系统中自带的一些函数、第三方函数、以及用户自定义的函数,那么Python如何编写函数?我们通过这篇文章来介绍一下。函数是一组可重复使用的代码块,用于执行特定的任务。它们可以接受......
  • pandas-ai 基于LLM进行数据分析的python 框架
    pandas-ai基于LLM进行数据分析的python框架包含的特性基于自然语言的数据查询数据可视化数据清理特征生成数据链接(支持链接多种不同的数据源)说明对于基于数据分析的场景pandas-ai是一个值得尝试的工具,同时官方也微调了一个BambooLLM的模型(基于mistral)目前也已经在huggingface......
  • 【python爬虫案例】利用python爬取豆瓣电影TOP250评分排行数据!
    目录一、爬取对象-豆瓣电影TOP250二、豆瓣电影网站分析三、python爬虫代码详解三、完整源码获取一、爬取对象-豆瓣电影TOP250今天给大家分享一期豆瓣读书TOP排行榜250的python爬虫案例爬取的目标网址是:豆瓣电影Top250咱们以目标为驱动,以兴趣为导向,先来看下爬虫程......
  • trafilatura python web 数据获取库
    trafilaturapythonweb数据获取库,比较适合进行爬虫,数据提取,支持输出数据为csv,json,html,md,txt,xml包含的特性高级web爬虫以及文本发现并行处理在线以及离线输入内容灵活的配置支持,包含了元数据,格式,链接,表格多输出格式,包含了文本,markdown,json,html,xml额外扩展,支持语言检测,gui,速度优化......
  • 基于CNN-LSTM-Attention的共享单车租赁预测研究(数据可换)(Python代码实现)基于CNN-LSTM
                        ......
  • python 时间占位符 毫秒
    在Python中,可以使用datetime模块来处理时间和日期,并结合strftime方法来格式化时间字符串,包括毫秒。strftime方法中使用%f来表示微秒,要表示毫秒,需要对获取到的微秒数除以1000,然后格式化为3位数字。以下是一个示例代码,展示如何获取当前时间,并使用strftime格式化时间,包括毫秒:fromdate......
  • 当代码遇上“意外”:Python中的异常引发艺术
    引言异常处理是软件开发不可或缺的一部分。良好的异常管理不仅能够提升程序的稳定性与可靠性,还能显著改善用户体验。在Python中,“异常的引发”是指主动抛出一个错误信息,以通知调用者当前操作出现了问题。掌握这一技巧,对于编写高效、可维护的代码至关重要。基础语法介绍在Python......