YOLOv7_pose-Openvino和ONNXRuntime推理【CPU】

纯检测系列
YOLOv5-Openvino和ONNXRuntime推理【CPU】
YOLOv6-Openvino和ONNXRuntime推理【CPU】
YOLOv8-Openvino和ONNXRuntime推理【CPU】
YOLOv7-Openvino和ONNXRuntime推理【CPU】
YOLOv9-Openvino和ONNXRuntime推理【CPU】
跟踪系列
YOLOv5/6/7-Openvino-ByteTrack【CPU】
YOLOv8/9-Openvino-ByteTrack【CPU】
分割系列
YOLOv5_seg-Openvino和ONNXRuntime推理【CPU】
YOLOv8_seg-Openvino和ONNXRuntime推理【CPU】
关键点系列
YOLOv7_pose-Openvino和ONNXRuntime推理【CPU】
YOLOv8_pose-Openvino和ONNXRuntime推理【CPU】

注:YOLOv5、YOLOv6和YOLOv7代码内容基本一致!YOLOv8和YOLOv9代码内容基本一致!
全部代码Github:https://github.com/Bigtuo/YOLOv8_Openvino

1 环境:

CPU:i5-12500
Python:3.8.18

2 安装Openvino和ONNXRuntime

2.1 Openvino简介

Openvino是由Intel开发的专门用于优化和部署人工智能推理的半开源的工具包,主要用于对深度推理做优化。

Openvino内部集成了Opencv、TensorFlow模块,除此之外它还具有强大的Plugin开发框架,允许开发者在Openvino之上对推理过程做优化。

Openvino整体框架为:Openvino前端→ Plugin中间层→ Backend后端
Openvino的优点在于它屏蔽了后端接口,提供了统一操作的前端API,开发者可以无需关心后端的实现,例如后端可以是TensorFlow、Keras、ARM-NN,通过Plugin提供给前端接口调用,也就意味着一套代码在Openvino之上可以运行在多个推理引擎之上,Openvino像是类似聚合一样的开发包。

2.2 ONNXRuntime简介

ONNXRuntime是微软推出的一款推理框架,用户可以非常便利的用其运行一个onnx模型。ONNXRuntime支持多种运行后端包括CPU,GPU,TensorRT,DML等。可以说ONNXRuntime是对ONNX模型最原生的支持。

虽然大家用ONNX时更多的是作为一个中间表示,从pytorch转到onnx后直接喂到TensorRT或MNN等各种后端框架,但这并不能否认ONNXRuntime是一款非常优秀的推理框架。而且由于其自身只包含推理功能(最新的ONNXRuntime甚至已经可以训练),通过阅读其源码可以解深度学习框架的一些核心功能原理(op注册,内存管理,运行逻辑等)
总体来看,整个ONNXRuntime的运行可以分为三个阶段,Session构造,模型加载与初始化和运行。和其他所有主流框架相同,ONNXRuntime最常用的语言是python,而实际负责执行框架运行的则是C++。

2.3 安装

pip install openvino -i  https://pypi.tuna.tsinghua.edu.cn/simple
pip install onnxruntime -i  https://pypi.tuna.tsinghua.edu.cn/simple

3 YOLOv7介绍

YOLOv7详解-可爱版
YOLOv7官网

# pt2onnx,加grid是将三个头整合一起,不加则推理输出是各个头部输出,需要自己再写处理;end2end加了是包含nms,这里不加!
python export.py --weights yolov7.pt --grid  

4 基于Openvino和ONNXRuntime推理

下面代码整个处理过程主要包括:预处理—>推理—>后处理—>画图(矩形框和关键点)。
假设图像resize为640×640,
前处理输出结果维度:(1, 3, 640, 640);
推理输出结果维度:(1, 25500, 57),其中57表示4个box坐标信息+置信度分数+1个类别概率+17个关键点信息(x,y,visibility),8400表示80×80+40×40+20×20+10×10;
后处理输出结果维度:(-1, 56),其中第一个维度表示检测的目标数量,第二个维度56表示(x1, y1, x2, y2, conf, 17×3);

注:该YOLOv7w6-pose包括P6输出头。

4.1 全部代码

import argparse
import time 
import cv2
import numpy as np
from openvino.runtime import Core  # pip install openvino -i  https://pypi.tuna.tsinghua.edu.cn/simple
import onnxruntime as ort  # 使用onnxruntime推理用上,pip install onnxruntime,默认安装CPU# Pose默认的person类
CLASSES = ['person']class OpenvinoInference(object):def __init__(self, onnx_path):self.onnx_path = onnx_pathie = Core()self.model_onnx = ie.read_model(model=self.onnx_path)self.compiled_model_onnx = ie.compile_model(model=self.model_onnx, device_name="CPU")self.output_layer_onnx = self.compiled_model_onnx.output(0)def predict(self, datas):predict_data = self.compiled_model_onnx([datas])[self.output_layer_onnx]return predict_dataclass KeyPoint_draw(object):def __init__(self):# 定义一个调色板数组,其中每个元素是一个包含RGB值的列表,用于表示不同的颜色self.palette = np.array([[255, 128, 0], [255, 153, 51], [255, 178, 102],[230, 230, 0], [255, 153, 255], [153, 204, 255],[255, 102, 255], [255, 51, 255], [102, 178, 255],[51, 153, 255], [255, 153, 153], [255, 102, 102],[255, 51, 51], [153, 255, 153], [102, 255, 102],[51, 255, 51], [0, 255, 0], [0, 0, 255], [255, 0, 0],[255, 255, 255]])# 定义人体17个关键点的连接顺序,每个子列表包含两个数字,代表要连接的关键点的索引, 1鼻子 2左眼 3右眼 4左耳 5右耳 6左肩 7右肩# 8左肘 9右肘 10左手腕 11右手腕 12左髋 13右髋 14左膝 15右膝 16左踝 17右踝self.skeleton = [[16, 14], [14, 12], [17, 15], [15, 13], [12, 13], [6, 12],[7, 13], [6, 7], [6, 8], [7, 9], [8, 10], [9, 11], [2, 3],[1, 2], [1, 3], [2, 4], [3, 5], [4, 6], [5, 7]]# 通过索引从调色板中选择颜色,用于绘制人体骨架的线条,每个索引对应一种颜色self.pose_limb_color = self.palette[[9, 9, 9, 9, 7, 7, 7, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16]]# 通过索引从调色板中选择颜色,用于绘制人体的关键点,每个索引对应一种颜色self.pose_kpt_color = self.palette[[16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9]]def plot_skeleton_kpts(self, im, kpts, steps=3):num_kpts = len(kpts) // steps  # 51 / 3 =17# 画点for kid in range(num_kpts):r, g, b = self.pose_kpt_color[kid]x_coord, y_coord = kpts[steps * kid], kpts[steps * kid + 1]conf = kpts[steps * kid + 2]if conf > 0.5:  # 关键点的置信度必须大于 0.5cv2.circle(im, (int(x_coord), int(y_coord)), 10, (int(r), int(g), int(b)), -1)# 画骨架for sk_id, sk in enumerate(self.skeleton):r, g, b = self.pose_limb_color[sk_id]pos1 = (int(kpts[(sk[0] - 1) * steps]), int(kpts[(sk[0] - 1) * steps + 1]))pos2 = (int(kpts[(sk[1] - 1) * steps]), int(kpts[(sk[1] - 1) * steps + 1]))conf1 = kpts[(sk[0] - 1) * steps + 2]conf2 = kpts[(sk[1] - 1) * steps + 2]if conf1 > 0.5 and conf2 > 0.5:  # 对于肢体,相连的两个关键点置信度 必须同时大于 0.5cv2.line(im, pos1, pos2, (int(r), int(g), int(b)), thickness=2)class YOLOv7_pose:"""YOLOv7_pose detection model class for handling inference and visualization."""def __init__(self, onnx_model, imgsz=(640, 640), infer_tool='openvino'):"""Initialization.Args:onnx_model (str): Path to the ONNX model."""self.infer_tool = infer_toolif self.infer_tool == 'openvino':# 构建openvino推理引擎self.openvino = OpenvinoInference(onnx_model)self.ndtype = np.singleelse:# 构建onnxruntime推理引擎self.ort_session = ort.InferenceSession(onnx_model,providers=['CUDAExecutionProvider', 'CPUExecutionProvider']if ort.get_device() == 'GPU' else ['CPUExecutionProvider'])# Numpy dtype: support both FP32 and FP16 onnx modelself.ndtype = np.half if self.ort_session.get_inputs()[0].type == 'tensor(float16)' else np.singleself.classes = CLASSES  # 加载模型类别self.model_height, self.model_width = imgsz[0], imgsz[1]  # 图像resize大小self.color = (0, 0, 255)  # 为类别生成调色板def __call__(self, im0, conf_threshold=0.4, iou_threshold=0.45):"""The whole pipeline: pre-process -> inference -> post-process.Args:im0 (Numpy.ndarray): original input image.conf_threshold (float): confidence threshold for filtering predictions.iou_threshold (float): iou threshold for NMS.Returns:boxes (List): list of bounding boxes."""# 前处理Pre-processt1 = time.time()im, ratio, (pad_w, pad_h) = self.preprocess(im0)print('预处理时间:{:.3f}s'.format(time.time() - t1))# 推理 inferencet2 = time.time()if self.infer_tool == 'openvino':preds = self.openvino.predict(im)else:preds = self.ort_session.run(None, {self.ort_session.get_inputs()[0].name: im})[0]print('推理时间:{:.2f}s'.format(time.time() - t2))# 后处理Post-processt3 = time.time()boxes = self.postprocess(preds,im0=im0,ratio=ratio,pad_w=pad_w,pad_h=pad_h,conf_threshold=conf_threshold,iou_threshold=iou_threshold,)print('后处理时间:{:.3f}s'.format(time.time() - t3))return boxes# 前处理,包括:resize, pad, HWC to CHW,BGR to RGB,归一化,增加维度CHW -> BCHWdef preprocess(self, img):"""Pre-processes the input image.Args:img (Numpy.ndarray): image about to be processed.Returns:img_process (Numpy.ndarray): image preprocessed for inference.ratio (tuple): width, height ratios in letterbox.pad_w (float): width padding in letterbox.pad_h (float): height padding in letterbox."""# Resize and pad input image using letterbox() (Borrowed from Ultralytics)shape = img.shape[:2]  # original image shapenew_shape = (self.model_height, self.model_width)r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])ratio = r, rnew_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))pad_w, pad_h = (new_shape[1] - new_unpad[0]) / 2, (new_shape[0] - new_unpad[1]) / 2  # wh paddingif shape[::-1] != new_unpad:  # resizeimg = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)top, bottom = int(round(pad_h - 0.1)), int(round(pad_h + 0.1))left, right = int(round(pad_w - 0.1)), int(round(pad_w + 0.1))img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=(114, 114, 114))  # 填充# Transforms: HWC to CHW -> BGR to RGB -> div(255) -> contiguous -> add axis(optional)img = np.ascontiguousarray(np.einsum('HWC->CHW', img)[::-1], dtype=self.ndtype) / 255.0img_process = img[None] if len(img.shape) == 3 else imgreturn img_process, ratio, (pad_w, pad_h)# 后处理,包括:阈值过滤与NMSdef postprocess(self, preds, im0, ratio, pad_w, pad_h, conf_threshold, iou_threshold):"""Post-process the prediction.Args:preds (Numpy.ndarray): predictions come from ort.session.run().im0 (Numpy.ndarray): [h, w, c] original input image.ratio (tuple): width, height ratios in letterbox.pad_w (float): width padding in letterbox.pad_h (float): height padding in letterbox.conf_threshold (float): conf threshold.iou_threshold (float): iou threshold.Returns:boxes (List): list of bounding boxes."""x = preds  # outputs: predictions (1, 25500, 57),其中57=4+1+1+17*3,17个关键点(x,y,visibility)# Predictions filtering by conf-thresholdx = x[x[..., 4] > conf_threshold]# Create a new matrix which merge these(box, score, pose) into one# For more details about `numpy.c_()`: https://numpy.org/doc/1.26/reference/generated/numpy.c_.htmlx = np.c_[x[..., :4], x[..., 4], x[..., 6:]]# NMS filtering# 经过NMS后的值, np.array([[x, y, w, h, conf, pose], ...]), shape=(-1, 4 + 1 + 17*3)x = x[cv2.dnn.NMSBoxes(x[:, :4], x[:, 4], conf_threshold, iou_threshold)]# 重新缩放边界框,为画图做准备if len(x) > 0:# Bounding boxes format change: cxcywh -> xyxyx[..., [0, 1]] -= x[..., [2, 3]] / 2x[..., [2, 3]] += x[..., [0, 1]]# Rescales bounding boxes from model shape(model_height, model_width) to the shape of original imagex[..., :4] -= [pad_w, pad_h, pad_w, pad_h]x[..., :4] /= min(ratio)# Bounding boxes boundary clampx[..., [0, 2]] = x[:, [0, 2]].clip(0, im0.shape[1])  # clip避免边界框超出图像边界x[..., [1, 3]] = x[:, [1, 3]].clip(0, im0.shape[0])# 关键点坐标映射到原图上,从[:, 5:]开始算num_kpts = x.shape[1] // 3  # 56 // 3 = 18for kid in range(2, num_kpts + 1):x[:, kid * 3 - 1] = (x[:, kid * 3 - 1] - pad_w) / min(ratio)x[:, kid * 3] = (x[:, kid * 3] - pad_h) / min(ratio)return xelse:return []# 绘框def draw_and_visualize(self, im, bboxes, keypoint_draw, vis=False, save=True):"""Draw and visualize results.Args:im (np.ndarray): original image, shape [h, w, c].bboxes (numpy.ndarray): [n, 56], n is number of bboxes.vis (bool): imshow using OpenCV.save (bool): save image annotated.Returns:None"""# Draw rectangles for bbox in bboxes:box, conf, kpts = bbox[:4], bbox[4], bbox[5:]# draw bbox rectanglecv2.rectangle(im, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])),self.color, 1, cv2.LINE_AA)cv2.putText(im, f'{self.classes[0]}: {conf:.3f}', (int(box[0]), int(box[1] - 9)),cv2.FONT_HERSHEY_SIMPLEX, 0.7, self.color, 2, cv2.LINE_AA)# 画关键点,连线keypoint_draw.plot_skeleton_kpts(im, kpts)# Show imageif vis:cv2.imshow('demo', im)cv2.waitKey(0)cv2.destroyAllWindows()# Save imageif save:cv2.imwrite('demo.jpg', im)if __name__ == '__main__':# Create an argument parser to handle command-line argumentsparser = argparse.ArgumentParser()parser.add_argument('--model', type=str, default='weights/yolov7-w6-pose.onnx', help='Path to ONNX model')parser.add_argument('--source', type=str, default=str('bus.jpg'), help='Path to input image')parser.add_argument('--imgsz', type=tuple, default=(640, 640), help='Image input size')parser.add_argument('--conf', type=float, default=0.25, help='Confidence threshold')parser.add_argument('--iou', type=float, default=0.45, help='NMS IoU threshold')parser.add_argument('--infer_tool', type=str, default='openvino', choices=("openvino", "onnxruntime"), help='选择推理引擎')args = parser.parse_args()# Build modelmodel = YOLOv7_pose(args.model, args.imgsz, args.infer_tool)keypoint_draw = KeyPoint_draw()  # 可视化关键点# Read image by OpenCVimg = cv2.imread(args.source)# Inferenceboxes = model(img, conf_threshold=args.conf, iou_threshold=args.iou)# Visualizeif len(boxes) > 0:model.draw_and_visualize(img, boxes, keypoint_draw, vis=False, save=True)

4.2 结果

在这里插入图片描述

具体时间消耗:

预处理时间:0.005s(包含Pad)
推理时间:0.32s(Openvino)
推理时间:0.38s(ONNXRuntime)
后处理时间:0.001s
注:640×640下。

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

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

相关文章

如何打造知识管理平台,只需了解这几点

随着企业的发展,知识资源日益丰富和复杂,如果不加以有效管理和整合,这些知识很可能会被埋没或丢失。打造知识管理平台可以将这些知识资源进行统一存储和分类,便于员工查找和使用,从而充分发挥知识的价值。有很多工具可…

细说C++反向迭代器:原理与用法

文章目录 一、引言二、反向迭代器的原理与实现细节三、模拟实现C反向迭代器反向迭代器模板类的设计反向迭代器的使用示例与测试 一、引言 迭代器与反向迭代器的概念引入 迭代器(Iterator)是C标准模板库(STL)中的一个核心概念&am…

matplotlib-直方图

日期:2024.03.114 内容:将matplotlib的常用方法做一个记录,方便后续查找。 # 引入需要的库 from matplotlib import pyplot as plt import numpy as np# 设置画布大小 plt.figure(figsize (20,8),dpi 200)# 全局设置中文字体 plt.rcParams…

Android NDK入门:在应用中加入C和C++的力量

目录 ​编辑 引 NDK的设计目的 与Java/Kotlin的结合 使用场景 开发流程 设置项目以支持NDK 编写本地代码 使用JNI连接本地代码和Java/Kotlin代码 编译和运行你的应用 附 引 自诩方向是android方向的移动端开发工程师,却从来没有真正仔细了解过NDK&#…

Swift:.ignoresSafeArea():自由布局的全方位掌握

ignoresSafeArea(_ regions : edges:)修饰符的说明 SwiftUI布局系统会调整视图的尺寸和位置,以避免特定的安全区域。这就确保了系统内容(比如软件键盘)或设备边缘不会遮挡您的视图。要将您的内容扩展到这些区域,您可以通过应用该修…

植物神经功能紊乱患者每天从5片黛力新减少至2片,只因找对了治疗方法!

植物神经功能紊乱是一种常见的心理疾病,其症状包括焦虑、失眠、疲劳、头痛、胃肠不适等,给患者带来很大的困扰。然而,这种疾病是可以治疗的。本文将介绍一位植物神经功能紊乱患者的治疗经历,希望能够帮助更多的人了解和治疗此病。…

生成二维码及加入logo和文字

<html> <!-- 存放二维码的容器 --> <div idqrcode></div> <script typetext/javascript srchttp://cdn.staticfile.org/jquery/2.1.1/jquery.min.js></script> <script src"https://cdn.bootcss.com/jquery.qrcode/1.0/jquery.qr…

Three.js基础入门介绍——Three.js学习七【播放模型动画时模型沿着轨迹移动】

效果描述 在播放导入的模型动画同时&#xff0c;让模型沿着预定路径轨迹移动。例如导入一个会跑步动作的模型&#xff0c;让它沿着一条类似跑道的路径跑步移动。 实现流程 基本流程 1、搭建场景 2、添加模型和播放动画 3、添加路径和模型移动 工程文件 工程文件结构如下图&…

谁用过腾讯云轻量应用服务器2核2G3M配置,支持多少人在线?

腾讯云轻量应用服务器2核4G5M配置一年优惠价165元、252元15个月、三年756元&#xff0c;100%CPU性能&#xff0c;5M带宽下载速度640KB/秒&#xff0c;60GB SSD系统盘&#xff0c;月流量500GB&#xff0c;折合每天16.6GB流量&#xff0c;超出月流量包的流量按照0.8元每GB的价格支…

常用芯片学习——TP4057电源管理芯片

TP40578 500mA线性锂离子电池充电器 芯片介绍 TP4057是一款性能优异的单节锂离子电池恒流/恒压线性充电器。TP4057采用S0T23-6封装配合较少的外围原件使其非常适用于便携式产品&#xff0c;并且适合给USB电源以及适配器电源供电。 基于特殊的内部MOSFET架构以及防倒充电路&a…

Python实现一笔画游戏

Python实现一笔画游戏 关于一笔画介绍可参见“HTML5实现一笔画游戏”https://blog.csdn.net/cnds123/article/details/136669088 在Python中&#xff0c;Tkinter是一个广泛使用的标准GUI库&#xff0c;我们将使用它来实现这个游戏。 先给出效果图&#xff1a; 连接线段时&am…

城乡居民基本医疗信息管理系统|基于Springboot的城乡居民基本医疗信息管理系统设计与实现(源码+数据库+文档)

城乡居民基本医疗信息管理系统目录 目录 基于Springboot的城乡居民基本医疗信息管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1、病例管理 2、医院资讯信息管理 3、医院资讯类型管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选…

微信小程序开发学习笔记《21》uni-app框架-楼层图片跳转

微信小程序开发学习笔记《21》uni-app框架-楼层图片跳转 博主正在学习微信小程序开发&#xff0c;希望记录自己学习过程同时与广大网友共同学习讨论。建议仔细阅读uni-app对应官方文档 一、创建新的分包goods_list 二、将请求到的楼层数据url调整为本地的 可以看到上图是请求…

关于固件的简单解释

我不喜欢等人也不喜欢被别人等——赤砂之蝎 简而言之 固件是什么 固件&#xff08;Firmware&#xff09;是一种软件类型&#xff0c;它是嵌入式系统中的一部分&#xff0c;通常存储在设备的非易失性存储器中&#xff0c;如闪存或ROM&#xff08;只读存储器&#xff09;。与操作…

libevent中bufferevent事件及常用的API函数

自带buffer的事件-bufferevent bufferevent实际上也是一个event&#xff0c;只不过比普通的event高级&#xff0c;他的内部有两个缓冲区&#xff0c;以及一个文件描述符&#xff08;网络套接字&#xff09;。一个网络套接字有读写两个缓冲区&#xff0c;bufferevent同样也带有…

探索仿函数(Functor):C++中的灵活函数对象

文章目录 一、仿函数定义及使用二、仿函数与函数指针的区别三、仿函数与算法的关系四、仿函数的实践用例 在C编程中&#xff0c;我们经常需要对数据进行排序、筛选或者其他操作。为了实现这些功能&#xff0c;C标准库提供了许多通用的算法和容器&#xff0c;而其中一个重要的概…

nut-ui组件库icon中使用阿里图标

1.需求 基本每个移动端组件库都有组件 icon组件 图标组件、 但是很多组件库中并找不到我们需要的图标 这时候 大家有可能会找图标库 最大众的就是iconfont的图标了 2.使用 有很多方式去使用这个东西 比如将再限链接中的css引入 在使用 直接下载图标 symbol 方式 等....…

【NR 定位】3GPP NR Positioning 5G定位标准解读(十三)-DL-AoD定位

前言 3GPP NR Positioning 5G定位标准&#xff1a;3GPP TS 38.305 V18 3GPP 标准网址&#xff1a;Directory Listing /ftp/ 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;一&#xff09;-CSDN博客 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;…

buuctf warmup 超详细

目录 1.代码审计&#xff1a; 2.逻辑分析 3.总结分析 4.分析记录 5.疑点解答 1.代码审计&#xff1a; <?phphighlight_file(__FILE__);class emmm //定义了一个类{public static function checkFile(&$page) 类里面又申明创建…

Android 架构师研发技术进阶之路:不同阶段需要掌握的那些技术及软技能

资深 而到了资深层次&#xff0c;技术栈已经不再是阻碍。能够从更高层面看待问题&#xff0c;理解整个系统的设计&#xff0c;作为系统架构师的角色存在。 1. 理解微服务、SOA思想&#xff0c;对于后端开发有一定涉猎。 2. 了解前端研发工具和思想&#xff0c;知道vue react…