RF-DETR实现onnx推理(Python版)

RF-DETR实现onnx推理(Python版)

本文不生产技术,只做技术的搬运工!!!

前言

        上篇文章完成了RF-DETR本地推理和自建数据集训练的介绍,但是推理太慢了,需要加一下速,本文章介绍如何实现onnx推理。训练及环境配置参考:

https://blog.ZEEKLOG.net/qq_44908396/article/details/154522731https://blog.ZEEKLOG.net/qq_44908396/article/details/154522731

环境补充

        配置训练环境时,有一些包没有安装,这里进行一些补充,就记得这几个了,其余的忘了,大家缺啥补啥吧,反正都是pip安装。

conda activate rf-detr pip install onnx pip install onnxruntime pip install onnxsim

onnx模型导出

from rfdetr import RFDETRBase,RFDETRLarge,RFDETRNano,RFDETRSmall,RFDETRMedium model = RFDETRNano(pretrain_weights="/home/project_python/rf-detr/runs/nano/checkpoint_best_total.pth") model.export(output_dir = "/home/project_python/rf-detr/runs/nano/")

onnx模型推理

        这里作者实现了两个版本的预处理,一个使用torch一个使用numpy,经过测试,torch预处理的图像推理效果与pt模型推理效果一致,numpy版本推理结果与pt模型略有出入,但影响不大,由于工程端一般不使用torch,大家可以选择numpy版本的预处理,将其转换成C++代码进行部署。

import cv2 import onnxruntime import numpy as np import random import time import torchvision.transforms.functional as F def xywh2xyxy(x): """ 将边界框坐标从 (x, y, width, height) 转换为 (x1, y1, x2, y2) Args: x (np.ndarray): 输入边界框数组 Returns: np.ndarray: 转换后的边界框数组 """ 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 softmax(x): """ Softmax函数 Args: x (np.ndarray): 输入数组 Returns: np.ndarray: 经过softmax处理的数组 """ e_x = np.exp(x - np.max(x)) return e_x / e_x.sum(axis=0) def sigmoid(x): """ Sigmoid函数 Args: x (np.ndarray): 输入数组 Returns: np.ndarray: 经过sigmoid处理的数组 """ return 1 / (1 + np.exp(-x)) def get_optimal_font_scale(image_shape, text, font_face=cv2.FONT_HERSHEY_SIMPLEX): """ 根据图像分辨率自动计算最优字体大小 """ # 获取图像的最小边长 min_dimension = min(image_shape[0], image_shape[1]) # 基于图像尺寸计算基础字体大小 base_font_scale = min_dimension / 1000.0 # 确保字体大小在合理范围内 font_scale = max(0.5, min(base_font_scale, 2.0)) return font_scale def generate_distinct_color(): """ 生成具有明显区分度的随机颜色 """ # 使用HSV色彩空间生成颜色,确保颜色具有较高的饱和度和亮度 h = random.randint(0, 179) # OpenCV中色调范围是0-179 s = random.randint(150, 255) # 饱和度:150-255 (避免过淡的颜色) v = random.randint(150, 255) # 亮度:150-255 (避免过暗的颜色) # 将HSV转换为BGR hsv = np.uint8([[[h, s, v]]]) bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) return tuple(int(x) for x in bgr[0][0]) def get_color_for_class(class_id, color_map): """ 为类别ID获取颜色,如果不存在则生成新颜色 """ if class_id not in color_map: color_map[class_id] = generate_distinct_color() return color_map[class_id] def preprocess_image(image, target_size=(384, 384)): """ 预处理图像 Args: image (np.ndarray): 输入图像 target_size (tuple): 目标图像尺寸 Returns: tuple: (处理后的图像, 缩放因子, 原始尺寸) """ # 保存原始尺寸 h, w = image.shape[:2] w_rate = w / target_size[0] h_rate = h / target_size[1] # 调整图像大小 resized_image = cv2.resize(image, target_size,interpolation=cv2.INTER_LINEAR) # 颜色空间转换和归一化 rgb_image = cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB) normalized_image = rgb_image.astype(np.float32) / 255.0 # 标准化 mean = [0.485, 0.456, 0.406] std = [0.229, 0.224, 0.225] normalized_image = (normalized_image - mean) / std # 转换维度并扩展批次维度 processed_image = np.transpose(normalized_image, (2, 0, 1)) processed_image = np.expand_dims(processed_image, axis=0).astype(np.float32) return processed_image, (w_rate, h_rate), (w, h) def preprocess_image_torch(image, target_size=(384, 384)): """ 预处理图像 Args: image (np.ndarray): 输入图像 target_size (tuple): 目标图像尺寸 Returns: tuple: (处理后的图像, 缩放因子, 原始尺寸) """ img_tensor = image img_tensor = F.to_tensor(img_tensor).to("cuda:0") h, w = img_tensor.shape[1:] mean = [0.485, 0.456, 0.406] std = [0.229, 0.224, 0.225] img_tensor = F.normalize(img_tensor, mean, std) img_tensor = F.resize(img_tensor, target_size) # 保存原始尺寸 h, w = image.shape[:2] w_rate = w / target_size[0] h_rate = h / target_size[1] return np.expand_dims(img_tensor.cpu().numpy(), axis=0).astype(np.float32), (w_rate, h_rate), (w, h) def postprocess_detections(bboxes, labels, target_size=(384, 384)): """ 后处理检测结果 Args: bboxes (np.ndarray): 边界框数组 labels (np.ndarray): 标签数组 target_size (tuple): 目标图像尺寸 Returns: list: 处理后的检测结果列表 """ results = [] for i in range(len(bboxes)): # 转换边界框格式 bbox = xywh2xyxy(bboxes[i]) # 缩放边界框坐标 bbox[0] *= target_size[1] # x坐标乘以宽度 bbox[2] *= target_size[1] # x坐标乘以宽度 bbox[1] *= target_size[0] # y坐标乘以高度 bbox[3] *= target_size[0] # y坐标乘以高度 # 应用softmax并获取类别和置信度 label_list = sigmoid(labels[i]) class_id = np.argmax(label_list) conf = label_list[class_id] results.append({ 'bbox': bbox, 'class_id': class_id, 'confidence': conf }) return results def draw_detections(image, detections, scale_factors, conf_threshold=0.5): """ 在图像上绘制检测结果 Args: image (np.ndarray): 输入图像 detections (list): 检测结果列表 scale_factors (tuple): 缩放因子 (w_rate, h_rate) conf_threshold (float): 置信度阈值 Returns: np.ndarray: 绘制了检测结果的图像 """ w_rate, h_rate = scale_factors result_image = image.copy() detection_count = 0 # 存储类别颜色的字典 color_map = {} # 根据图像分辨率自动调整字体大小 font_scale = get_optimal_font_scale(image.shape, "SampleText") thickness = max(1, int(font_scale * 2)) # 根据字体大小调整线条粗细 for detection in detections: conf = detection['confidence'] if conf > conf_threshold: detection_count += 1 bbox = detection['bbox'] class_id = detection['class_id'] # 为每个类别ID获取颜色 color = get_color_for_class(class_id, color_map) # 在原始尺寸图像上绘制框 x1 = int(bbox[0] * w_rate) y1 = int(bbox[1] * h_rate) x2 = int(bbox[2] * w_rate) y2 = int(bbox[3] * h_rate) # 绘制边界框 cv2.rectangle(result_image, (x1, y1), (x2, y2), color, thickness) # 在同一行显示类别名称和置信度,带背景色 label = f"{class_id} {conf:.2f}" # 计算文本尺寸 (text_width, text_height), baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, font_scale, thickness) # 绘制文本背景框 cv2.rectangle(result_image, (x1, y1 - text_height - baseline - 2), (x1 + text_width, y1), color, -1) # 绘制文本 cv2.putText(result_image, label, (x1, y1 - baseline), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (255, 255, 255), thickness) print(f"检测框: 类别={class_id}, 置信度={conf:.2f}") print(f"总共检测到 {detection_count} 个置信度高于阈值的目标") return result_image def run_detection(model_path, image_path, conf_threshold=0.5): """ 运行目标检测 Args: model_path (str): ONNX模型路径 image_path (str): 图像路径 conf_threshold (float): 置信度阈值 """ # 初始化模型 model = onnxruntime.InferenceSession(model_path,providers=['CPUExecutionProvider']) # 读取图像 image = cv2.imread(image_path) src_image = image.copy() # 预处理图像 processed_image, scale_factors, original_size = preprocess_image(image) # 模型推理 start = time.time() output = model.run(["dets", "labels"], {"input": processed_image}) print(f"inference time: {time.time() - start}") bboxes = output[0][0] labels = output[1][0] # 后处理检测结果 detections = postprocess_detections(bboxes, labels) # 绘制检测结果 result_image = draw_detections(src_image, detections, scale_factors, conf_threshold) # 保存结果 cv2.imwrite("result_onnx.jpg", result_image) # 主程序 if __name__ == "__main__": model_path = "/home/project_python/rf-detr/runs/nano/inference_model.onnx" image_path = "/home/project_python/rf-detr/dataset/dtrain_20251030_v1/images/test/gacdbx_1_17424bef_1600_20251029113538995.jpg" start = time.time() run_detection(model_path, image_path, conf_threshold=0.9) print(f"total time: {time.time() - start}")

结语

        onnx模型推理速度为72ms每张,下篇文章将更新tensorrt推理。

Read more

Python 实战:Boss 直聘职位信息爬虫开发全解析​

Python 实战:Boss 直聘职位信息爬虫开发全解析​

在求职和职场数据分析场景中,获取结构化的职位信息能为我们提供极大的便利 —— 无论是对比薪资水平、分析行业需求,还是研究企业招聘偏好,都需要可靠的数据源支持。本文将手把手教你用 Python 开发一个 Boss 直聘爬虫,通过监听网络请求的方式高效获取职位数据,并将结果保存为 Excel 文件。 一、开发前准备:环境与工具 在开始编码前,我们需要搭建好开发环境并明确核心依赖库的作用,确保后续开发过程顺畅。 1. 环境要求 * Python 3.8 及以上版本(推荐 3.10,兼容性更好) * 浏览器:Chrome 或 Edge(需与 Chromium 内核驱动版本匹配) 2. 核心依赖库 本文爬虫主要依赖 4 个关键库,可通过pip install 库名命令安装: * DrissionPage:一款强大的浏览器自动化工具,支持控制浏览器、监听网络请求,

By Ne0inhk
用 python 开发一个可调用工具的 AI Agent,实现电脑配置专业评价

用 python 开发一个可调用工具的 AI Agent,实现电脑配置专业评价

在人工智能时代,AI Agent凭借其强大的任务处理能力,逐渐成为开发人员手中的得力工具。今天,我们就来一起动手,用Python打造一个能够调用工具的AI Agent,实现根据电脑信息对电脑配置进行专业评价的功能。 一、项目创建与目录结构 1.1 项目创建 首先,我们需要创建一个新的项目环境。这里使用UV进行项目创建。 uv init demo 项目创建完成后,进入项目文件夹并安装必要的包, 比如安装psutil uv add psutil 安装的包都会记录在pypoject.toml, 看看我都安装了哪些包 [project] name = "demo" version = "0.1.0" description = "Add your description here" readme = "README.

By Ne0inhk

windows 系统安装 python 的最好方式也许就是不安装

一、 核心问题 目前在windows机器上面安装python,去python官网下载下来的安装文件不是具体的某一个版本的python,而是一个叫做“python-manager-25.0.msix”东西 这个东西被称作为“python install manager” 并且后面这种方式安装python将成为windows系统安装python的主流方式,官网原文如下: The Python install manager for Windows is our tool for installing and managing runtimes. The traditional executable installer will stop being released with Python 3.16 As well as the files below, the Python install

By Ne0inhk