onnx快速部署YOLO模型

1、准备和环境

 首先需要将yolov5模型训练好的最佳权重文件转化为.onnx格式以备使用。不会的小伙伴可以参考yolov5的官方文档,使用yolov5官方的 export.py 脚本进行转换,或者参考一些博客链接,这里不做详细解析。
 基本环境配置,相比于yolov5模型源码部署,使用onnx的方式部署会省下不少配置环境的问题,只需要几个关键的第三方库即可完成。

numpy>=1.22.3
onnxruntime>=1.13.1
Pillow>=9.3.0
python-multipart>=0.0.5
fastapi>=0.88.0
python-multipart>=0.0.5
uvicorn[standard]

2、部署代码

2.1、main.py

 主文件主要调用

from PIL import Image,ImageDraw,ImageFont
from utils.operation import YOLO
from utils.Colors import colors
import numpy as np
from matplotlib import pyplot as plt
def draw_anchor(img,det_obj):img = Image.open(img)draw = ImageDraw.Draw(img)font = ImageFont.truetype('arial.ttf', 30)imgw,imgh = img.sizecolors_dt = dict() for i in range(len(det_obj)):if colors_dt.get(det_obj[i]['classes']) is None:colors_dt[det_obj[i]['classes']] = colors(i,True)draw.rectangle(det_obj[i]['crop'],width=3,outline=colors_dt[det_obj[i]['classes']])x1, y1, x2, y2 = tuple(det_obj[i]['crop'])draw.text((x1,y1-35),det_obj[i]['classes'],fill=colors_dt[det_obj[i]['classes']],font=font)imgarr = np.array(img)plt.imshow(imgarr)plt.show()img.show() 
def detect(onnx_path='ReqFile/yolov5s.onnx',img=r'ReqFile/bus.jpg',show=True):'''检测目标,返回目标所在坐标如:{'crop': [57, 390, 207, 882], 'classes': 'person'},...]:param onnx_path:onnx模型路径:param img:检测用的图片:param show:是否展示'''#加载yoloyolo = YOLO(onnx_path=onnx_path)  # 加载yolo类#检测det_obj = yolo.decect(img,conf_thres=0.5, iou_thres=0.25)  # 检测#画锚框draw_anchor(img,det_obj)
if __name__ == '__main__':detect()pass

2.2、operation.py

from io import BytesIOimport onnxruntime
import numpy as np
from PIL import Imagefrom utils.orientation import non_max_suppression, tag_imagesclass ONNXModel(object):def __init__(self, onnx_path):""":param onnx_path:"""self.onnx_session = onnxruntime.InferenceSession(onnx_path)self.input_name = self.get_input_name(self.onnx_session)self.output_name = self.get_output_name(self.onnx_session)def get_output_name(self, onnx_session):"""output_name = onnx_session.get_outputs()[0].name:param onnx_session::return:"""output_name = []for node in onnx_session.get_outputs():output_name.append(node.name)return output_namedef get_input_name(self, onnx_session):"""input_name = onnx_session.get_inputs()[0].name:param onnx_session::return:"""input_name = []for node in onnx_session.get_inputs():input_name.append(node.name)return input_namedef get_input_feed(self, input_name, image_numpy):"""input_feed={self.input_name: image_numpy}:param input_name::param image_numpy::return:"""input_feed = {}for name in input_name:input_feed[name] = image_numpyreturn input_feeddef to_numpy(self, file, shape, gray=False):if isinstance(file, np.ndarray):img = Image.fromarray(file)elif isinstance(file, bytes):img = Image.open(BytesIO(file))passelse:img = Image.open(file)widht, hight = shape# 改变大小 并保证其不失真img = img.convert('RGB')if gray:img = img.convert('L')img = img.resize((widht, hight), Image.ANTIALIAS)# 转换成矩阵image_numpy = np.array(img) # (widht, hight, 3)if gray:image_numpy = np.expand_dims(image_numpy,0)image_numpy = image_numpy.transpose(0, 1, 2)else:image_numpy = image_numpy.transpose(2,0,1) # 转置 (3, widht, hight)image_numpy = np.expand_dims(image_numpy,0)# 数据归一化image_numpy = image_numpy.astype(np.float32) / 255.0return image_numpy
class YOLO(ONNXModel):def __init__(self, onnx_path="ReqFile/yolov5n-7-k5.onnx"):super(YOLO, self).__init__(onnx_path)# 训练所采用的输入图片大小self.img_size = 640self.img_size_h = self.img_size_w = self.img_sizeself.batch_size = 1#数量self.num_classes = 2#标签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 to_numpy(self, file, shape, gray=False):def letterbox_image(image, size):iw, ih = image.sizew, h = sizescale = min(w / iw, h / ih)nw = int(iw * scale)nh = int(ih * scale)image = image.resize((nw, nh), Image.BICUBIC)new_image = Image.new('RGB', size, (128, 128, 128))new_image.paste(image, ((w - nw) // 2, (h - nh) // 2))return new_imageif isinstance(file, np.ndarray):img = Image.fromarray(file)elif isinstance(file, bytes):img = Image.open(BytesIO(file))else:img = Image.open(file)resized = letterbox_image(img, (self.img_size_w, self.img_size_h))img_in = np.transpose(resized, (2, 0, 1)).astype(np.float32)  # HWC -> CHWimg_in = np.expand_dims(img_in, axis=0)img_in /= 255.0return img_indef decect(self, file,conf_thres=0.25, iou_thres=0.45):# 图片转换为矩阵image_numpy = self.to_numpy(file, shape=(self.img_size, self.img_size))input_feed = self.get_input_feed(self.input_name, image_numpy)outputs = self.onnx_session.run(self.output_name, input_feed=input_feed)pred = non_max_suppression(outputs[0],conf_thres, iou_thres)if pred:res = tag_images(np.array(Image.open(file)), pred, self.img_size, self.classes)else:res = []return res

2.3、orientation.py

import time
import numpy as np
#用于控制Python中小数的显示精度
np.set_printoptions(precision=4)
def rescale_boxes(boxes, current_dim, original_shape):""" Rescales bounding boxes to the original shape """orig_h, orig_w = original_shape# The amount of padding that was addedpad_x = max(orig_h - orig_w, 0) * (current_dim / max(original_shape))pad_y = max(orig_w - orig_h, 0) * (current_dim / max(original_shape))# Image height and width after padding is removedunpad_h = current_dim - pad_yunpad_w = current_dim - pad_x# Rescale bounding boxes to dimension of original imageboxes[:, 0] = ((boxes[:, 0] - pad_x // 2) / unpad_w) * orig_wboxes[:, 1] = ((boxes[:, 1] - pad_y // 2) / unpad_h) * orig_hboxes[:, 2] = ((boxes[:, 2] - pad_x // 2) / unpad_w) * orig_wboxes[:, 3] = ((boxes[:, 3] - pad_y // 2) / unpad_h) * orig_hreturn boxes
def tag_images(imgs, img_detections, img_size, classes):imgs = [imgs]results = []for img_i, (img, detections) in enumerate(zip(imgs, img_detections)):# Create plotif detections is not None:# Rescale boxes to original imagedetections = rescale_boxes(detections, img_size, img.shape[:2])for x1, y1, x2, y2, conf, cls_pred in detections:results.append({"crop": [int(i) for i in (x1, y1, x2, y2)],"classes": classes[int(cls_pred)]})else:print("识别失败")return results
# 识别结果解析
def xywh2xyxy(x):# Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] # where xy1=top-left, xy2=bottom-righty = np.copy(x)y[:, 0] = x[:, 0] - x[:, 2] / 2  # top left xy[:, 1] = x[:, 1] - x[:, 3] / 2  # top left yy[:, 2] = x[:, 0] + x[:, 2] / 2  # bottom right xy[:, 3] = x[:, 1] + x[:, 3] / 2  # bottom right yreturn y
def nms(dets, scores, thresh):"""Pure Python NMS baseline."""# x1、y1、x2、y2、以及score赋值x1 = dets[:, 0]  # xminy1 = dets[:, 1]  # yminx2 = dets[:, 2]  # xmaxy2 = dets[:, 3]  # ymaxareas = (x2 - x1 + 1) * (y2 - y1 + 1)# argsort()返回数组值从小到大的索引值order = scores.argsort()[::-1]keep = []while order.size > 0:  # 还有数据i = order[0]keep.append(i)if order.size == 1: break# 计算当前概率最大矩形框与其他矩形框的相交框的坐标xx1 = np.maximum(x1[i], x1[order[1:]])yy1 = np.maximum(y1[i], y1[order[1:]])xx2 = np.minimum(x2[i], x2[order[1:]])yy2 = np.minimum(y2[i], y2[order[1:]])# 计算相交框的面积w = np.maximum(0.0, xx2 - xx1 + 1)h = np.maximum(0.0, yy2 - yy1 + 1)inter = w * h# 计算重叠度IOU:重叠面积/(面积1+面积2-重叠面积)IOU = inter / (areas[i] + areas[order[1:]] - inter)left_index = (np.where(IOU <= thresh))[0]# 将order序列更新,由于前面得到的矩形框索引要比矩形框在原order序列中的索引小1,所以要把这个1加回来order = order[left_index + 1]return np.array(keep)def non_max_suppression(prediction, conf_thres, iou_thres, classes=None, agnostic=False, multi_label=False,labels=()):"""Runs Non-Maximum Suppression (NMS) on inference resultsReturns:list of detections, on (n,6) tensor per image [xyxy, conf, cls]"""nc = prediction.shape[2] - 5xc = prediction[..., 4] > conf_thres  # candidates# Settingsmin_wh, max_wh = 2, 4096  # (pixels) minimum and maximum box width and heightmax_det = 300  # maximum number of detections per imagemax_nms = 30000  # maximum number of boxes into torchvision.ops.nms()time_limit = 10.0  # seconds to quit afterredundant = True  # require redundant detectionsmulti_label &= nc > 1  # multiple labels per box (adds 0.5ms/img)t = time.time()output = [np.zeros((0, 6))] * prediction.shape[0]for xi, x in enumerate(prediction):x = x[xc[xi]]  # confidence# Cat apriori labels if autolabellingif labels and len(labels[xi]):l = labels[xi]v = np.zeros((len(l), nc + 5))v[:, :4] = l[:, 1:5]  # boxv[:, 4] = 1.0  # confv[range(len(l)), l[:, 0].long() + 5] = 1.0  # clsx = np.concatenate((x, v), 0)# If none remain process next imageif not x.shape[0]:continue# Compute confx[:, 5:] *= x[:, 4:5]  # conf = obj_conf * cls_conf# Box (center x, center y, width, height) to (x1, y1, x2, y2)box = xywh2xyxy(x[:, :4])if multi_label:i, j = (x[:, 5:] > conf_thres).nonzero()x = np.concatenate((box[i], x[i, j + 5, None], j[:, None]), 1)else:  # best class onlyconf = x[:, 5:].max(1, keepdims=True)j = x[:, 5:].argmax(1)j = np.expand_dims(j, 0).Tx = np.concatenate((box, conf, j), 1)[conf.reshape(1, -1)[0] > conf_thres]# Filter by classif classes is not None:x = x[(x[:, 5:6] == np.array(classes)).any(1)]# Check shapen = x.shape[0]  # number of boxesif not n:  # no boxescontinueelif n > max_nms:  # excess boxesx = x[x[:, 4].argsort(descending=True)[:max_nms]]  # sort by confidence# Batched NMSc = x[:, 5:6] * (0 if agnostic else max_wh)  # classesboxes, scores = x[:, :4] + c, x[:, 4]  # boxes (offset by class), scoresi = nms(boxes, scores, iou_thres)  # NMSif i.shape[0] > max_det:  # limit detectionsi = i[:max_det]output[xi] = x[i]if (time.time() - t) > time_limit:print(f'WARNING: NMS time limit {time_limit}s exceeded')break  # time limit exceededreturn output

3、测试

在这里插入图片描述

完整文件请参考:
https://pan.baidu.com/s/1X1DiywM8yJtBzysKfzqbcA
提取码:6666

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/181483.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

谱方法学习笔记-上(超详细)

谱方法学习笔记&#x1f4d2; 谱方法学习笔记-下(超详细) 声明&#xff1a;鉴于CSDN使用 K a T e X KaTeX KaTeX 渲染公式&#xff0c; KaTeX \KaTeX KATE​X 与 L a T e X LaTeX LaTeX 不同&#xff0c;不支持直接的交叉引用命令&#xff0c;如\label和\eqref。 KaTeX \KaT…

详解STUN与TR111

STUN协议定义了三类测试过程来检测NAT类型&#xff1a; Test1&#xff1a;STUN Client通过端口{IP-C1:Port-C1}向STUN Server{IP-S1:Port-S1}发送一个Binding Request&#xff08;没有设置任何属性&#xff09;。STUN Server收到该请求后&#xff0c;通过端口{IP-S1:Port-S1}把…

【区块链】产品经理的NFT初探

常见的FT如比特币&#xff08;BTC&#xff09;&#xff0c;以太币&#xff08;ETH&#xff09;等&#xff0c;两个代币之间是完全可替换的。而NFT具有唯一性&#xff0c;不可以互相替换。本文作者对NET的发展现状、相关协议、应用场景等方面进行了分析&#xff0c;一起来看一下…

论如何让Spring Boot在高压力环境下依然与众不同

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容调优线程池优化线程池配置多样化设备支持分布式控制同步编程 &#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客…

【论文阅读】An Experimental Survey of Missing Data Imputation Algorithms

论文地址&#xff1a;An Experimental Survey of Missing Data Imputation Algorithms | IEEE Journals & Magazine | IEEE Xplore 处理缺失数据最简单的方法就是是丢弃缺失值的样本&#xff0c;但这会使得数据更加不完整并且导致偏差或影响结果的代表性。因此&#xff0c;…

HTTP协议,Web框架回顾

HTTP 请求协议详情 -请求首行---》请求方式&#xff0c;请求地址&#xff0c;请求协议版本 -请求头---》key:value形式 -referer&#xff1a;上一次访问的地址 -user-agenet&#xff1a;客户端类型 -name&#xff1a;lqz -cookie&…

500元价位开放式耳机哪款好用、百元价位开放式耳机推荐

经常佩戴入耳式耳机的朋友应该都遇到过耳朵肿胀的感觉&#xff0c;这个时候&#xff0c;就是耳朵在告诉你&#xff0c;该休息一会了。如果耳朵里经常塞着耳机听歌&#xff0c;时间久了很容易引起听力衰退等问题&#xff0c;这是不可逆的伤害。各位朋友如果和我一样每天都戴着耳…

1120:最值交换

题目描述 有一个长度为n的整数序列。请写一个程序&#xff0c;先把序列中的最小值与第一个数交换&#xff0c;再把最大值与最后一个数交换。输出转换好的序列。 分别编写两个函数MinIndex()和MaxIndex()来计算最小值下标和最大值下标。 int MinIndex(int a[], int n); //函数返…

C++基础 -12- 拷贝构造(浅拷贝)

系统会自动生成浅拷贝&#xff0c;就相当于直接赋值 #include "iostream"using namespace std;class base { public:base(int a, int b) : a(a), b(b){}int a;int b; }; int main() {base newbase1(10, 20);base newbase2 newbase1;cout << newbase1.a <…

数据库的增删查改(CRUD)基础版

CRUD: create增加、retrieve查询、update更新、delete删除 注意一点&#xff1a;MySQL对大小写是不敏感的 目录 新增&#xff08;create&#xff09; 全列插入 指定列插入 多行插入 查询&#xff08;Retrieve&#xff09; 列查询 全列查询 指定列查询 表达式查询 …

wsl 命令详解

WSL 简介 WSL全称 Windows Subsystem for Linux &#xff0c;是微软开发的一个运行在Windows上的兼容层&#xff0c;它允许开发人员和用户直接在Windows上运行原生Linux二进制文件&#xff0c;而无需配置或修改系统。 WSL命令是用于管理和操作WSL子系统的工具。 常用WSL命令…

系统设计概念:生产 Web 应用的架构

在你使用的每个完美应用程序背后&#xff0c;都有一整套的架构、测试、监控和安全措施。今天&#xff0c;让我们来看看一个生产就绪应用程序的非常高层次的架构。 CI/CD 管道 我们的第一个关键领域是持续集成和持续部署——CI/CD 管道。 这确保我们的代码从存储库经过一系列测试…

Java核心知识点整理大全22-笔记

目录 19.1.14. CAP 一致性&#xff08;C&#xff09;&#xff1a; 可用性&#xff08;A&#xff09;&#xff1a; 分区容忍性&#xff08;P&#xff09;&#xff1a; 20. 一致性算法 20.1.1. Paxos Paxos 三种角色&#xff1a;Proposer&#xff0c;Acceptor&#xff0c;L…

YOLOv8独家原创改进:自研独家创新MSAM注意力,通道注意力升级,魔改CBAM

💡💡💡本文自研创新改进:MSAM(CBAM升级版):通道注意力具备多尺度性能,多分支深度卷积更好的提取多尺度特征,最后高效结合空间注意力 1)作为注意力MSAM使用; 推荐指数:五星 MSCA | 亲测在多个数据集能够实现涨点,对标CBAM。 在道路缺陷检测任务中,原始ma…

VMware通过ISO镜像安装window2016虚拟机

1.点文件->新建虚拟机 2.进入到下边页面 3.根据你的服务器硬件选择硬件兼容性 4.选择2016版本的windows(注&#xff1a;没有该版本的话选择最高版本) 5.根据你的需求选择引导设备( 启动过程&#xff1a; BIOS&#xff1a; 在计算机启动时&#xff0c;BIOS负责进行自检&#…

华天动力-OA8000 MyHttpServlet 文件上传漏洞复现

0x01 产品简介 华天动力OA是一款将先进的管理思想、 管理模式和软件技术、网络技术相结合&#xff0c;为用户提供了低成本、 高效能的协同办公和管理平台。 0x02 漏洞概述 华天动力OA MyHttpServlet 存在任意文件上传漏洞&#xff0c;未经身份认证的攻击者可上传恶意的raq文件…

Kanna库代码示例

编写一个使用Kanna库的网络爬虫程序。以下是代码的详细解释&#xff1a; swift import Kanna // 创建一个对象 let proxy Proxy(host: ") // 创建一个Kanna对象 let kanna Kanna(proxy: proxy) // 创建一个请求对象 let request Request(url: "") // 使用…

【算法刷题】Day8

文章目录 202. 快乐数解法&#xff1a; 11. 盛最多水的容器解法&#xff1a; 202. 快乐数 原题链接 拿到题&#xff0c;我们先看题干 把一个整数替换为每个位置上的数字平方和&#xff0c;有两种情况&#xff1a; 重复这个过程始终不到 1&#xff08;无限死循环&#xff09;结…

python基于YOLOv7系列模型【yolov7-tiny/yolov7/yolov7x】开发构建钢铁产业产品智能自动化检测识别系统

在前文的项目开发实践中&#xff0c;我们已经以钢铁产业产品缺陷检测数据场景为基准&#xff0c;陆续开发构建了多款目标检测模型&#xff0c;感兴趣的话可以自行阅读即可。 《YOLOv3老矣尚能战否&#xff1f;基于YOLOv3开发构建建钢铁产业产品智能自动化检测识别系统&#xf…

专业的事交给专业的公司来做,文件销毁 数据销毁 硬盘销毁

在当今信息化社会&#xff0c;数据和文件已经成为企业和个人生活中不可或缺的一部分。然而&#xff0c;随着数据量的不断增长&#xff0c;如何确保数据的安全性和隐私性成为了一个亟待解决的问题。为了解决这个问题&#xff0c;文件销毁、硬盘销毁、数据销毁和物料销毁等技术应…