YOLOv8_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 YOLOv8介绍

YOLOv8官网
YOLOv8原理

4 基于Openvino和ONNXRuntime推理

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

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 YOLOv8_pose:"""YOLOv8_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, 56, 8400),其中56=4+1+17*3,17个关键点(x,y,visibility)# Transpose the first output: (Batch_size, xywh_conf_pose, Num_anchors) -> (Batch_size, Num_anchors, xywh_conf_pose)x = np.einsum('bcn->bnc', x)  # (1, 8400, 56)# 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[..., 5:]]# 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/yolov8s-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 = YOLOv8_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)

在这里插入图片描述

具体时间消耗:

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

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

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

相关文章

rtsp流实现web端实时播放(海康+大华)

最近的电力项目需要嵌入海康摄像头画面,之前没有做过类似的流媒体播放,所以有些懵; 海康开放平台的webAPI,有插件还是无插件,都不适合自研web系统的嵌入,所以需要自己进行解流; 首先&#xff0c…

企业即时通讯工具,企业内部即时通讯系统推荐

企业需要私有化即时通讯系统主要出于以下几个方面的考虑, 数据安全和隐私保护:在企业日常办公中,涉及到大量的敏感信息和机密数据,这些信息如果通过公共即时通讯工具传输,存在被窃取或泄露的风险。通过私有化即时通讯…

如何将Git拉取项目后,将SSH验证方式修改为HTTPS?

首先在打开项目所在位置的Git BashGUI 查找当前的远程仓库URL: 打开终端或命令提示符,导航到你的项目目录,并使用以下命令查看当前配置的远程仓库URL: git remote -v这会显示如下格式的输出: origin gitgithub.com:用…

Linux中GPU相关命令

Linux查看显卡信息: lspci | grep -i vga 使用nvidia GPU可以: lspci | grep -i nvidia1 前边的序号 "00:0f.0"是显卡的代号(这里是用的虚拟机); 查看指定显卡的详细信息用以下指令: lspci -v -s 00:0f.01 Linux查看Nvidia显…

RedisTemplate实现锁超时时间延长(模仿Redisson看门狗机制)

业务场景: 在上一篇-Java业务功能并发问题处理的最后,我们用RedisTemplate实现了一个分布式锁,但是后面又有用户反馈同个单据出现了重复操作,让我们回忆下上次的加锁代码: 问题描述: 原因出现在我们锁住…

【开源工程】超经典实景三维数字孪生矿山~智慧矿山解决方案

飞渡科技数字孪生煤矿管理平台,以数字孪生技术为底座,融合图像识别、电磁感应、5G下井等技术,实现矿山环境、采煤装备、移动巡检等生产数据的全面采集,实时感知生产过程与关键装备的运行数据和状态,逐步推进矿山全流程…

Python爬虫从基础到入门:script标签中的数据

上一篇文章: Python爬虫从基础到入门:script标签中的数据 1. 分析需要抓取的数据的在哪?2. 获取数据、解析数据3. 下载视频、音频文件4. 参考代码1. 分析需要抓取的数据的在哪? 本篇博文以B站视频为例,B站视频在用户没有登录的状态下,只能观看视频尺寸为360流畅,在登录…

深度剖析Kafka中Coordinator的奥秘

欢迎来到我的博客,代码的世界里,每一行都是一个故事 深度剖析Kafka中Coordinator的奥秘 前言什么是Coordinator?Group Coordinator(群组协调器):Transaction Coordinator(事务协调器&#xff09…

一文让您读懂实时数仓(Apache Doris)

引言: 随着大数据时代的来临,实时数据处理与分析成为企业核心竞争力的关键因素之一。在这场数据革命中,SelectDB成为引领者。从百度自研的实时数仓平台 Palo,到开源项目 Apache Doris,再到飞轮科技研发的 SelectDB&am…

程序人生——Java数组和集合使用建议(1)

目录 引出数组和集合建议60:性能考虑,数组是首选建议61:若有必要,使用变长数组建议62:警惕数组的浅拷贝 建议63:在明确的场景下,为集合指定初始容量建议64:多种最值算法,…

使用opencv进行图片分析

opencv学习 一、配置环境并打开编译器 配置opencv在你的任意一个盘里创建一个专属于opencv的文件夹便于学习与整理 打开控制台winr输入cmd,进入后输入conda activate opencv,进入环境以后进入你所设置的opencv文件的盘,我的是D盘&#xff0…

php.exe运行时,提示缺少VCRUNTIME140.dll

php.exe运行时,提示缺少VCRUNTIME140.dll 下载地址 https://www.microsoft.com/zh-cn/download/details.aspx?id48145根据需要选择下载3.运行安装后,再次运行php.exe。

javaweb篇请求与相应的参数问题

目录 目录 前言 简单传参设置 get请求无法识别 post请求 简单传参问题无法识别的解决问题 注意事项 改法 实体参数 代码展示(1)------单个私有类 代码展示(2)----多个私有类 实现服务器的部署以及实参的传递 今日分享…

B3620 x 进制转 10 进制(详解)

题目 思路 八进制数567怎么转化为十进制数。首先八进制就是逢八进一,也就是说这里面最大的数也就7,没有≥8的数。下面我们就讲一下567怎么转化为十进制:首先7是个位,可以直接写成十进制的7,6是十位,它是通…

图片制作二维码能批量生成吗?快捷在线制作二维码的技巧

现在很多场景下获取内容的方式都会通过扫描二维码来获取,比如常见的有文本内容、图片照片、音频视频等。二维码制作的方法也越来越简单,只需要通过二维码生成器的功能就可以快速完成,那么如果需要将多张图片每一张单独生成二维码使用时&#…

虚幻引擎5比Maya更好用吗?来看看Maya大神眼中的虚幻引擎5

这两年,大家总在争论: 虚幻引擎5(UE5)比Maya更好用吗? 未来会替代Maya吗? 虚幻引擎5(UE5)的快速发展,让许多传统Maya动画师感到焦虑和迷茫。但不要担心,这篇文章旨在解决你的困扰。…

Springboot——JSR303校验

1. 请求参数的合法性校验 使用基于JSR303的校验框架实现,Springboot提供了JSR-303的支持,它就是spring-boot-starter-validation,他包括了很多的校验规则,只需要在模型中通过注解指定校验规则,在Controller方法上开启校…

激活函数理解

前言 为什么神经网中非要有各种各样的激活函数?他们有什么用?没有他们会怎样?常见的激活函数有哪些,他们都有什么特点? 如果我们不运用激活函数,神经网络的输出信号将仅仅是一个简单的线性函数。线性方程…

Docker 容器化技术:构建高效、可移植的开发环境和部署流程|Docker 网络

为了支持网络协议栈的多个实例,Linux 在网络协议栈中引入了网络命名空间。这些独立的协议栈被隔离到不同的命名空间中,处于不同命名空间中的网络协议栈是完全隔离的,彼此无法通信。通过对网络资源的隔离,就能在一台宿主机上虚拟多…

FFmepg--视频编码流程--yuv编码为h264

文章目录 基本概念流程api核心代码 基本概念 YUV格式:是一种颜色编码方式,YUV分别为三个分量:‘Y’是明亮度,也就是灰度值;‘U’和‘V’是色度 YUV格式的分类: planar的YUV格式:先存储planar的…