主要讲的是ONNX-ONNX Runtime部署
我之前因为是讲torchserve服务器部署
来着,但是发现本部分视频还没拍摄,torchserve服务器部署
还等待催更(狗头,本部分内容原本应该如下:
anyway,现在只有第一个文件夹,不过由于我确实对这部分比较陌生,会看部分相关解说博客,我文中会放置相关链接。
什么是ONNX-ONNX Runtime,找到了一个大佬的解说(这篇文章写的很好,可看):
转自:模型部署之ONNX ONNXRuntime
前面看不懂的同学可以简单理解如下:
但是肯定不会那么简单,由于没有其他部署的对比,先姑且这么理解吧
安装Pytorch
!pip3 install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu113
安装工具包
!pip install numpy pandas matplotlib tqdm opencv-python pillow onnx onnxruntime -i https://pypi.tuna.tsinghua.edu.cn/simple
把原生Pytorch训练得到的图像分类模型
,导出为ONNX格式
,用于后续在ONNX Runtime推理引擎
上部署。
导入工具包
import torch
from torchvision import models
# 有 GPU 就用 GPU,没有就用 CPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print('device', device)
载入lmageNet预训练图像分类模型
model = models.resnet18(pretrained=True)
model = model.eval().to(device)
x = torch.randn(1, 3, 256, 256).to(device)
output = model(x)
output.shape
#torch.Size([1, 1000])
Pytorch模型转ONNX模型
x = torch.randn(1, 3, 256, 256).to(device)
with torch.no_grad():
torch.onnx.export(
model, # 要转换的模型
x, # 模型的任意一组输入
'resnet18.onnx', # 导出的 ONNX 文件名
opset_version=11, # ONNX 算子集版本
input_names=['input'], # 输入 Tensor 的名称(自己起名字)
output_names=['output'] # 输出 Tensor 的名称(自己起名字)
)
Tensor这里是张量
,相关文章:
笔记│什么是张量(tensor)&深度学习
验证oonx模型导出成功
import onnx
# 读取 ONNX 模型
onnx_model = onnx.load('resnet18.onnx')
# 检查模型格式是否正确
onnx.checker.check_model(onnx_model)
print('无报错,onnx模型载入成功')
以可读的形式打印计算图
print(onnx.helper.printable_graph(onnx_model.graph))
这个图蛮漂亮的(数学上的好看),贴出来:
graph torch-jit-export (
%input[FLOAT, 1x3x256x256]
) initializers (
%fc.weight[FLOAT, 1000x512]
%fc.bias[FLOAT, 1000]
%193[FLOAT, 64x3x7x7]
%194[FLOAT, 64]
%196[FLOAT, 64x64x3x3]
%197[FLOAT, 64]
%199[FLOAT, 64x64x3x3]
%200[FLOAT, 64]
%202[FLOAT, 64x64x3x3]
%203[FLOAT, 64]
%205[FLOAT, 64x64x3x3]
%206[FLOAT, 64]
%208[FLOAT, 128x64x3x3]
%209[FLOAT, 128]
%211[FLOAT, 128x128x3x3]
%212[FLOAT, 128]
%214[FLOAT, 128x64x1x1]
%215[FLOAT, 128]
%217[FLOAT, 128x128x3x3]
%218[FLOAT, 128]
%220[FLOAT, 128x128x3x3]
%221[FLOAT, 128]
%223[FLOAT, 256x128x3x3]
%224[FLOAT, 256]
%226[FLOAT, 256x256x3x3]
%227[FLOAT, 256]
%229[FLOAT, 256x128x1x1]
%230[FLOAT, 256]
%232[FLOAT, 256x256x3x3]
%233[FLOAT, 256]
%235[FLOAT, 256x256x3x3]
%236[FLOAT, 256]
%238[FLOAT, 512x256x3x3]
%239[FLOAT, 512]
%241[FLOAT, 512x512x3x3]
%242[FLOAT, 512]
%244[FLOAT, 512x256x1x1]
%245[FLOAT, 512]
%247[FLOAT, 512x512x3x3]
%248[FLOAT, 512]
%250[FLOAT, 512x512x3x3]
%251[FLOAT, 512]
) {
%192 = Conv[dilations = [1, 1], group = 1, kernel_shape = [7, 7], pads = [3, 3, 3, 3], strides = [2, 2]](%input, %193, %194)
%125 = Relu(%192)
%126 = MaxPool[ceil_mode = 0, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [2, 2]](%125)
%195 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%126, %196, %197)
%129 = Relu(%195)
%198 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%129, %199, %200)
%132 = Add(%198, %126)
%133 = Relu(%132)
%201 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%133, %202, %203)
%136 = Relu(%201)
%204 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%136, %205, %206)
%139 = Add(%204, %133)
%140 = Relu(%139)
%207 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [2, 2]](%140, %208, %209)
%143 = Relu(%207)
%210 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%143, %211, %212)
%213 = Conv[dilations = [1, 1], group = 1, kernel_shape = [1, 1], pads = [0, 0, 0, 0], strides = [2, 2]](%140, %214, %215)
%148 = Add(%210, %213)
%149 = Relu(%148)
%216 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%149, %217, %218)
%152 = Relu(%216)
%219 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%152, %220, %221)
%155 = Add(%219, %149)
%156 = Relu(%155)
%222 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [2, 2]](%156, %223, %224)
%159 = Relu(%222)
%225 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%159, %226, %227)
%228 = Conv[dilations = [1, 1], group = 1, kernel_shape = [1, 1], pads = [0, 0, 0, 0], strides = [2, 2]](%156, %229, %230)
%164 = Add(%225, %228)
%165 = Relu(%164)
%231 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%165, %232, %233)
%168 = Relu(%231)
%234 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%168, %235, %236)
%171 = Add(%234, %165)
%172 = Relu(%171)
%237 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [2, 2]](%172, %238, %239)
%175 = Relu(%237)
%240 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%175, %241, %242)
%243 = Conv[dilations = [1, 1], group = 1, kernel_shape = [1, 1], pads = [0, 0, 0, 0], strides = [2, 2]](%172, %244, %245)
%180 = Add(%240, %243)
%181 = Relu(%180)
%246 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%181, %247, %248)
%184 = Relu(%246)
%249 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%184, %250, %251)
%187 = Add(%249, %181)
%188 = Relu(%187)
%189 = GlobalAveragePool(%188)
%190 = Flatten[axis = 1](%189)
%240 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%175, %241, %242)
%243 = Conv[dilations = [1, 1], group = 1, kernel_shape = [1, 1], pads = [0, 0, 0, 0], strides = [2, 2]](%172, %244, %245)
%180 = Add(%240, %243)
%181 = Relu(%180)
%246 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%181, %247, %248)
%184 = Relu(%246)
%249 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%184, %250, %251)
%187 = Add(%249, %181)
%188 = Relu(%187)
%189 = GlobalAveragePool(%188)
%190 = Flatten[axis = 1](%189)
%output = Gemm[alpha = 1, beta = 1, transB = 1](%190, %fc.weight, %fc.bias)
return %output
}
使用推理引擎 ONNX Runtime
,读取 onnx 格式
的模型文件,对单张图像文件进行预测。
应用场景:
以下代码在需要部署的硬件
上运行
只需把onnx模型文件
发到部署硬件上,并安装ONNX Runtime环境
,用几行代码就可以运行模型了。
import onnxruntime
import numpy as np
import torch
载入onnx模型,获取ONNX Runtime推理器
ort_session = onnxruntime.InferenceSession('resnet18.onnx')
构造输入,获取输出结果
x = torch.randn(1, 3, 256, 256).numpy()
x.shape
#(1, 3, 256, 256)
##注意,输入输出张量的名称需要和 torch.onnx.export 中设置的输入输出名对应
# onnx runtime 输入
ort_inputs = {'input': x}
# onnx runtime 输出
ort_output = ort_session.run(['output'], ort_inputs)[0]
ort_output.shape
#(1, 1000)
预处理
from torchvision import transforms
# 测试集图像预处理-RCTN:缩放裁剪、转 Tensor、归一化
test_transform = transforms.Compose([transforms.Resize(256),
transforms.CenterCrop(256),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
载入测试图像
img_path = 'banana1.jpg'
# 用 pillow 载入
from PIL import Image
img_pil = Image.open(img_path)
print(img_pil)
运行预处理
input_img = test_transform(img_pil)
input_img.shape
#torch.Size([3, 256, 256])
input_tensor = input_img.unsqueeze(0).numpy()
input_tensor.shape
#(1, 3, 256, 256)
# ONNX Runtime 输入
ort_inputs = {'input': input_tensor}
# ONNX Runtime 输出
pred_logits = ort_session.run(['output'], ort_inputs)[0]
pred_logits = torch.tensor(pred_logits)
pred_logits.shape
#torch.Size([1, 1000])
import torch.nn.functional as F
pred_softmax = F.softmax(pred_logits, dim=1) # 对 logit 分数做 softmax 运算
pred_softmax.shape
#torch.Size([1, 1000])
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=(8,4))
x = range(1000)
y = pred_softmax.cpu().detach().numpy()[0]
ax = plt.bar(x, y, alpha=0.5, width=0.3, color='yellow', edgecolor='red', lw=3)
plt.ylim([0, 1.0]) # y轴取值范围
# plt.bar_label(ax, fmt='%.2f', fontsize=15) # 置信度数值
plt.xlabel('Class', fontsize=20)
plt.ylabel('Confidence', fontsize=20)
plt.tick_params(labelsize=16) # 坐标文字大小
plt.title(img_path, fontsize=25)
plt.show()
后续步骤:解析top-n预测结果、在图像上写英文和中文预测结果
使用 ONNX Runtime 推理引擎,载入 ImageNet 预训练图像分类 onnx 模型,预测摄像头实时画面。
注意事项:
本代码需在连接摄像头的本地运行,不能在云GPU平台运行。
在本地运行
pip install onnxruntime
安装onnx runtime,并准备好onnx模型文件。
导入工具包
import onnxruntime
import torch
import pandas as pd
import numpy as np
from PIL import Image, ImageFont, ImageDraw
import matplotlib.pyplot as plt
%matplotlib inline
载入onnx模型,获取ONNX Runtime推理器
ort_session = onnxruntime.InferenceSession('resnet18.onnx')
载入lmageNet 1000图像分类标签
df = pd.read_csv('imagenet_class_index.csv')
idx_to_labels = {}
for idx, row in df.iterrows():
idx_to_labels[row['ID']] = row['class']
图像预处理
from torchvision import transforms
# 测试集图像预处理-RCTN:缩放裁剪、转 Tensor、归一化
test_transform = transforms.Compose([transforms.Resize(256),
transforms.CenterCrop(256),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
预测摄像头单帧画面
– 调用摄像头获取一帧画面
# 导入opencv-python
import cv2
import time
# 获取摄像头,传入0表示获取系统默认摄像头
cap = cv2.VideoCapture(1)
# 打开cap
cap.open(0)
time.sleep(1)
success, img_bgr = cap.read()
# 关闭摄像头
cap.release()
# 关闭图像窗口
cv2.destroyAllWindows()
– 画面转成 RGB的Pillow格式
img_bgr.shape
#(720, 1280, 3)
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # BGR转RGB
img_pil = Image.fromarray(img_rgb)
print(img_pil)
预处埋
input_img = test_transform(img_pil)
input_tensor = input_img.unsqueeze(0).numpy()
input_tensor.shape
#(1, 3, 256, 256)
ONNX Runtime预测
# onnx runtime 预测
# onnx runtime 输入
ort_inputs = {'input': input_tensor}
# onnx runtime 输出
pred_logits = ort_session.run(['output'], ort_inputs)[0]
pred_logits = torch.tensor(pred_logits)
pred_logits.shape
#torch.Size([1, 1000])
import torch.nn.functional as F
pred_softmax = F.softmax(pred_logits, dim=1) # 对 logit 分数做 softmax 运算
pred_softmax.shape
#torch.Size([1, 1000])
解析top-n预测结果的类别和置信度
n = 5
top_n = torch.topk(pred_softmax, n) # 取置信度最大的 n 个结果
confs = top_n[0].cpu().detach().numpy().squeeze()
confs
#array([0.1028311 , 0.04595807, 0.02947768, 0.02589989, 0.02027929],
#, dtype=float32)
pred_ids = top_n[1].cpu().detach().numpy().squeeze()
pred_ids
#array([788, 918, 617, 457, 937])
在图像上写英文
for i in range(len(confs)):
pred_class = idx_to_labels[pred_ids[i]]
text = '{:<15} {:>.3f}'.format(pred_class, confs[i])
# 图片,添加的文字,左上角坐标,字体,字体大小,颜色,线宽,线型
img_bgr = cv2.putText(img_bgr, text, (50, 80 + 80 * i), cv2.FONT_HERSHEY_SIMPLEX, 2.5, (0, 0, 255), 5, cv2.LINE_AA)
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # BGR转RGB
plt.imshow(img_rgb)
plt.show()
处理单帧画面的函数(英文)
# 处理帧函数
def process_frame(img):
'''
输入摄像头拍摄画面bgr-array,输出图像分类预测结果bgr-array
'''
# 记录该帧开始处理的时间
start_time = time.time()
## 画面转成 RGB 的 Pillow 格式
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR转RGB
img_pil = Image.fromarray(img_rgb) # array 转 PIL
## 预处理
input_img = test_transform(img_pil) # 预处理
input_tensor = input_img.unsqueeze(0).numpy()
## onnx runtime 预测
ort_inputs = {'input': input_tensor} # onnx runtime 输入
pred_logits = ort_session.run(['output'], ort_inputs)[0] # onnx runtime 输出
pred_logits = torch.tensor(pred_logits)
pred_softmax = F.softmax(pred_logits, dim=1) # 对 logit 分数做 softmax 运算
## 解析top-n预测结果的类别和置信度
top_n = torch.topk(pred_softmax, 5) # 取置信度最大的 n 个结果
pred_ids = top_n[1].cpu().detach().numpy().squeeze() # 解析预测类别
confs = top_n[0].cpu().detach().numpy().squeeze() # 解析置信度
# 在图像上写英文
for i in range(len(confs)):
pred_class = idx_to_labels[pred_ids[i]]
text = '{:<15} {:>.3f}'.format(pred_class, confs[i])
# 图片,添加的文字,左上角坐标,字体,字体大小,颜色,线宽,线型
img = cv2.putText(img, text, (50, 160 + 80 * i), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 4, cv2.LINE_AA)
# 记录该帧处理完毕的时间
end_time = time.time()
# 计算每秒处理图像帧数FPS
FPS = 1/(end_time - start_time)
# 图片,添加的文字,左上角坐标,字体,字体大小,颜色,线宽,线型
img = cv2.putText(img, 'FPS '+str(int(FPS)), (50, 80), cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 255), 4, cv2.LINE_AA)
return img
调用摄像头获取每帧(模板)
# 调用摄像头逐帧实时处理模板
# 不需修改任何代码,只需修改process_frame函数即可
# 同济子豪兄 2021-7-8
# 导入opencv-python
import cv2
import time
# 获取摄像头,传入0表示获取系统默认摄像头
cap = cv2.VideoCapture(1)
# 打开cap
cap.open(0)
# 无限循环,直到break被触发
while cap.isOpened():
# 获取画面
success, frame = cap.read()
if not success:
print('Error')
break
## !!!处理帧函数
frame = process_frame(frame)
# 展示处理后的三通道图像
cv2.imshow('my_window',frame)
if cv2.waitKey(1) in [ord('q'),27]: # 按键盘上的q或esc退出(在英文输入法下)
break
# 关闭摄像头
cap.release()
# 关闭图像窗口
cv2.destroyAllWindows()
也是要在本地运行的
和上面代码基本一样,除了
1.需要导入中文字体
# 下载中文字体文件
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/dataset/SimHei.ttf
# 导入中文字体,指定字号
font = ImageFont.truetype('SimHei.ttf', 32)
2.在处理单帧画面的函数
部分
中文:
# 在图像上写字
for i in range(len(confs)):
pred_class = idx_to_labels[pred_ids[i]]
text = '{:<15} {:>.3f}'.format(pred_class, confs[i])
# 文字坐标,中文字符串,字体,rgba颜色
draw.text((50, 100 + 50 * i), text, font=font, fill=(255, 0, 0, 1))
img = np.array(img_pil) # PIL 转 array
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) # RGB转BGR
英文:
# 在图像上写英文
for i in range(len(confs)):
pred_class = idx_to_labels[pred_ids[i]]
text = '{:<15} {:>.3f}'.format(pred_class, confs[i])
安装基础工具包
!pip install numpy pandas matplotlib tqdm opencv-python pillow onnx onnxruntime -i https://pypi.tuna.tsinghua.edu.cn/simple
安装Pytorch
!pip3 install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu113
创建目录
import os
# 存放测试图片
os.mkdir('test_img')
# 存放结果文件
os.mkdir('output')
# 存放训练得到的模型权重
os.mkdir('checkpoints')
# 下载测试图像文件 至 test_img 文件夹
# 草莓图像,来源:https://www.pexels.com/zh-cn/photo/4828489/
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/test/0818/test_草莓.jpg -P test_img
!wget https://zihao-openmmlab.obs.myhuaweicloud.com/20220716-mmclassification/test/0818/test_fruits.jpg -P test_img
!wget https://zihao-openmmlab.obs.myhuaweicloud.com/20220716-mmclassification/test/0818/test_orange_2.jpg -P test_img
!wget https://zihao-openmmlab.obs.myhuaweicloud.com/20220716-mmclassification/test/0818/test_bananan.jpg -P test_img
!wget https://zihao-openmmlab.obs.myhuaweicloud.com/20220716-mmclassification/test/0818/test_kiwi.jpg -P test_img
!wget https://zihao-openmmlab.obs.myhuaweicloud.com/20220716-mmclassification/test/0818/test_石榴.jpg -P test_img
!wget https://zihao-openmmlab.obs.myhuaweicloud.com/20220716-mmclassification/test/0818/test_orange.jpg -P test_img
!wget https://zihao-openmmlab.obs.myhuaweicloud.com/20220716-mmclassification/test/0818/test_lemon.jpg -P test_img
!wget https://zihao-openmmlab.obs.myhuaweicloud.com/20220716-mmclassification/test/0818/test_火龙果.jpg -P test_img
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/test/watermelon1.jpg -P test_img
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/test/banana1.jpg -P test_img
下载中文字体文件
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/dataset/SimHei.ttf
下载训练好的模型文件
# 下载样例模型文件
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/checkpoints/fruit30_pytorch_20220814.pth -P checkpoints
导入工具包
载入onnx模型,获取ONNX Runtime推理器
构造输入,获取输出结果
预处理
载入测试图像
运行预处理
ONNX Runtime预测
解析预测结果
(A中这部分是柱状图可视化)
– 载入类别和对应ID
idx_to_labels = np.load('idx_to_labels.npy', allow_pickle=True).item()
print(idx_to_labels)
{0: ‘哈密瓜’,
, 1: ‘圣女果’,
, 2: ‘山竹’,
, 3: ‘杨梅’,
, 4: ‘柚子’,
, 5: ‘柠檬’,
, 6: ‘桂圆’,
, 7: ‘梨’,
, 8: ‘椰子’,
, 9: ‘榴莲’,
, 10: ‘火龙果’,
, 11: ‘猕猴桃’,
, 12: ‘石榴’,
, 13: ‘砂糖橘’,
, 14: ‘胡萝卜’,
, 15: ‘脐橙’,
, 16: ‘芒果’,
, 17: ‘苦瓜’,
, 18: ‘苹果-红’,
, 19: ‘苹果-青’,
, 20: ‘草莓’,
, 21: ‘荔枝’,
, 22: ‘菠萝’,
, 23: ‘葡萄-白’,
, 24: ‘葡萄-红’,
, 25: ‘西瓜’,
, 26: ‘西红柿’,
, 27: ‘车厘子’,
, 28: ‘香蕉’,
, 29: ‘黄瓜’}
– 设置matplotlib中文字体
# Linux操作系统,例如 云GPU平台:https://featurize.cn/?s=d7ce99f842414bfcaea5662a97581bd1
# 如果遇到 SSL 相关报错,重新运行本代码块即可
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/dataset/SimHei.ttf -O /environment/miniconda3/lib/python3.7/site-packages/matplotlib/mpl-data/fonts/ttf/SimHei.ttf
!rm -rf /home/featurize/.cache/matplotlib
import matplotlib
matplotlib.rc("font",family='SimHei') # 中文字体
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=(22, 10))
x = idx_to_labels.values()
y = pred_softmax.cpu().detach().numpy()[0] * 100
width = 0.45 # 柱状图宽度
ax = plt.bar(x, y, width)
plt.bar_label(ax, fmt='%.2f', fontsize=15) # 置信度数值
plt.tick_params(labelsize=20) # 设置坐标文字大小
plt.title(img_path, fontsize=30)
plt.xticks(rotation=45) # 横轴文字旋转
plt.xlabel('类别', fontsize=20)
plt.ylabel('置信度', fontsize=20)
plt.show()
注意事项
本代码需在连接摄像头的本地
运行,不能在云GPU平台运行
导入工具包
导入中文字体
载入onnx模型,获取ONNX Runtime推理器
载入类别和ID对应字典
图像预处理
预测摄像头单帧画面
– 调用摄像头获取一帧画面
– 画面转成RGB的Pillow格式
img_bgr.shape #(720, 1280, 3)
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # BGR转RGB
img_pil = Image.fromarray(img_rgb)
print(img_pil)
预处理
ONNX Runtime预测
解析top-n预测结果的类别和置信度
在图像上写中文
处理单帧画面的函数(中文)
调用摄像头获取每帧(模板)