news 2026/4/18 12:36:14

ONNX推理代码示例:用Python调用cv_resnet18_ocr-detection模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ONNX推理代码示例:用Python调用cv_resnet18_ocr-detection模型

ONNX推理代码示例:用Python调用cv_resnet18_ocr-detection模型

OCR文字检测是计算机视觉中一项基础而关键的能力,尤其在文档数字化、票据识别、工业质检等场景中不可或缺。cv_resnet18_ocr-detection是一个轻量高效、专为中文文本检测优化的模型,由科哥基于ResNet-18主干网络与DB(Differentiable Binarization)检测头构建,并已完整支持ONNX格式导出。相比动辄数GB的大型OCR模型,它在保持高精度的同时显著降低了部署门槛——单张图片检测在普通GPU上仅需0.2秒,在CPU上也稳定控制在3秒内。

本文不讲原理推导,也不堆砌参数配置,而是聚焦一个最实际的问题:当你已经拿到导出的.onnx文件,如何用几行干净、可复用、无依赖陷阱的Python代码完成端到端推理?我们将从环境准备、图像预处理、模型加载、结果后处理到可视化展示,全程手把手拆解,每一步都附带可直接运行的代码片段和关键细节说明。无论你是刚接触ONNX的新手,还是需要快速集成OCR能力的工程人员,都能在这里找到即插即用的解决方案。

1. 环境准备与依赖安装

1.1 最小化依赖清单

该模型推理仅需三个核心库,无需PyTorch或TensorFlow等重量级框架:

  • onnxruntime:ONNX模型运行时(推荐使用GPU版onnxruntime-gpu,CPU版onnxruntime即可)
  • opencv-python:图像读取、缩放、通道转换
  • numpy:数值计算与数组操作

执行以下命令一键安装(以Ubuntu/CentOS为例):

pip install onnxruntime-gpu opencv-python numpy

验证安装:运行python -c "import onnxruntime as ort; print(ort.__version__)",若输出版本号(如1.18.0),说明安装成功。
注意:若使用CPU推理,请安装onnxruntime(非-gpu版本),避免因CUDA驱动缺失导致报错。

1.2 模型文件获取路径

根据镜像文档中的“ONNX导出”章节,模型默认导出至项目目录下的outputs/子目录,文件名形如model_800x800.onnx。请确认你已通过WebUI成功导出,并将该文件复制到你的Python工作目录,例如:

your_project/ ├── model_800x800.onnx ← 导出的ONNX模型 ├── test.jpg ← 待检测的测试图片 └── infer.py ← 本文将编写的推理脚本

2. 图像预处理:还原WebUI一致的输入逻辑

2.1 WebUI预处理流程解析

镜像文档明确指出,WebUI在推理前对输入图像执行了三步标准化处理:

  1. 尺寸归一化:将原始图像等比缩放至指定输入尺寸(如800×800),保持长宽比,并在短边方向进行零填充(padding),确保输入张量严格为正方形;
  2. 通道转换:BGR → RGB(OpenCV默认BGR,模型训练使用RGB);
  3. 归一化:像素值除以255.0,映射至[0, 1]区间,并调整维度顺序为(1, 3, H, W)(NCHW格式)。

这三步看似简单,但任何一步偏差都会导致检测框坐标偏移或置信度异常。我们将在代码中严格复现。

2.2 预处理函数实现(含注释)

以下函数完全复刻WebUI逻辑,支持任意输入尺寸(如640×640、1024×1024),并返回处理后的numpy数组及缩放比例信息(用于后续坐标还原):

import cv2 import numpy as np def preprocess_image(image_path, input_size=800): """ 对输入图像执行WebUI一致的预处理 :param image_path: 图片路径 :param input_size: 模型期望的输入尺寸(正方形,如800) :return: 处理后的numpy数组 (1, 3, H, W) 和缩放比例字典 """ # 1. 读取图像(BGR格式) img = cv2.imread(image_path) if img is None: raise ValueError(f"无法读取图片: {image_path}") h_orig, w_orig = img.shape[:2] # 2. 等比缩放 + 填充至input_size×input_size scale = input_size / max(h_orig, w_orig) h_new = int(h_orig * scale) w_new = int(w_orig * scale) img_resized = cv2.resize(img, (w_new, h_new)) # 创建全黑填充画布 pad_img = np.zeros((input_size, input_size, 3), dtype=np.uint8) # 将缩放后图像居中放置 pad_img[(input_size - h_new)//2:(input_size - h_new)//2 + h_new, (input_size - w_new)//2:(input_size - w_new)//2 + w_new] = img_resized # 3. BGR -> RGB -> 归一化 -> NCHW img_rgb = cv2.cvtColor(pad_img, cv2.COLOR_BGR2RGB) img_norm = img_rgb.astype(np.float32) / 255.0 img_nchw = np.transpose(img_norm, (2, 0, 1))[np.newaxis, ...] # (1, 3, H, W) # 返回处理后图像和缩放信息(用于后处理坐标还原) return img_nchw, { 'scale': scale, 'pad_h': (input_size - h_new) // 2, 'pad_w': (input_size - w_new) // 2, 'orig_shape': (h_orig, w_orig), 'resized_shape': (h_new, w_new) } # 示例调用 input_blob, meta = preprocess_image("test.jpg", input_size=800) print(f"输入张量形状: {input_blob.shape}") # 输出: (1, 3, 800, 800)

关键点说明

  • cv2.resize默认使用双线性插值,与WebUI一致;
  • 填充方式为上下左右对称填充,而非仅右侧/下侧,这是保证坐标计算准确的核心;
  • meta字典中存储的scalepad_hpad_w将在后处理阶段用于将模型输出的归一化坐标还原为原始图像坐标。

3. ONNX模型加载与推理执行

3.1 创建推理会话(Session)

ONNX Runtime提供两种执行提供者(Execution Provider):CPUExecutionProviderCUDAExecutionProvider。我们编写一个智能选择函数,自动检测CUDA可用性并启用GPU加速:

import onnxruntime as ort def create_inference_session(model_path): """ 创建ONNX推理会话,优先使用GPU(若可用) :param model_path: .onnx模型文件路径 :return: ort.InferenceSession对象 """ # 检查CUDA是否可用 providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] try: session = ort.InferenceSession(model_path, providers=providers) print(f" 已启用GPU加速,使用提供者: {session.get_providers()}") except Exception as e: print(f" GPU不可用,回退至CPU模式: {e}") session = ort.InferenceSession(model_path, providers=['CPUExecutionProvider']) return session # 加载模型 session = create_inference_session("model_800x800.onnx")

提示:若你使用的是onnxruntime(非-gpu版本),此函数将自动降级至CPU模式,无需修改代码。

3.2 执行单次推理

模型输入名为"input"(见镜像文档示例),输出通常包含两个张量:"pred_boxes"(检测框坐标)和"pred_scores"(置信度分数)。我们通过session.run()获取结果:

# 执行推理 outputs = session.run( output_names=["pred_boxes", "pred_scores"], input_feed={"input": input_blob} ) pred_boxes = outputs[0] # 形状: (N, 4),N为检测框数量 pred_scores = outputs[1] # 形状: (N,) print(f"检测到 {len(pred_boxes)} 个文本区域,最高置信度: {pred_scores.max():.3f}")

注意:不同ONNX导出版本输出名称可能略有差异(如"boxes""detection_boxes")。若报错KeyError,请先运行print(session.get_inputs())print(session.get_outputs())查看实际名称。

4. 后处理:从模型输出到可读坐标与文本

4.1 坐标还原:将归一化坐标映射回原始图像

模型输出的pred_boxes是归一化后的坐标(范围0~1),且基于800×800的填充图像。我们需要将其还原为原始图像上的像素坐标:

def postprocess_boxes(pred_boxes, pred_scores, meta, score_threshold=0.2): """ 后处理:过滤低分框 + 还原坐标至原始图像 :param pred_boxes: 模型输出的(N, 4)坐标,格式为[x1, y1, x2, y2] :param pred_scores: (N,) 置信度分数 :param meta: preprocess_image返回的元信息 :param score_threshold: 置信度过滤阈值(同WebUI默认0.2) :return: 过滤并还原后的坐标列表 [[x1,y1,x2,y2], ...] 和对应分数 """ # 1. 过滤低分框 valid_mask = pred_scores >= score_threshold boxes_valid = pred_boxes[valid_mask] scores_valid = pred_scores[valid_mask] # 2. 还原坐标(逆向执行预处理步骤) # a. 反向填充:减去pad偏移 boxes_valid[:, [0, 2]] -= meta['pad_w'] # x方向 boxes_valid[:, [1, 3]] -= meta['pad_h'] # y方向 # b. 反向缩放:除以scale boxes_valid /= meta['scale'] # c. 截断至原始图像边界(防止越界) h_orig, w_orig = meta['orig_shape'] boxes_valid[:, [0, 2]] = np.clip(boxes_valid[:, [0, 2]], 0, w_orig) boxes_valid[:, [1, 3]] = np.clip(boxes_valid[:, [1, 3]], 0, h_orig) return boxes_valid.astype(int).tolist(), scores_valid.tolist() # 执行后处理 boxes, scores = postprocess_boxes(pred_boxes, pred_scores, meta, score_threshold=0.2) print(f"过滤后保留 {len(boxes)} 个有效检测框")

4.2 可视化检测结果(可选但强烈推荐)

将检测框绘制在原始图像上,是验证推理正确性的最快方式:

def visualize_result(image_path, boxes, scores, output_path="result.jpg"): """ 在原始图像上绘制检测框并保存 :param image_path: 原始图片路径 :param boxes: 还原后的坐标列表 [[x1,y1,x2,y2], ...] :param scores: 对应置信度列表 :param output_path: 输出图片路径 """ img = cv2.imread(image_path) for i, (box, score) in enumerate(zip(boxes, scores)): x1, y1, x2, y2 = box # 绘制绿色矩形框 cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) # 在框上方绘制置信度标签 label = f"{score:.2f}" cv2.putText(img, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(output_path, img) print(f" 可视化结果已保存至: {output_path}") # 调用可视化 visualize_result("test.jpg", boxes, scores)

效果验证:生成的result.jpg应与WebUI中“检测结果”Tab页显示的标注图高度一致,框体位置精准,无明显偏移。

5. 完整可运行脚本与使用说明

5.1 整合所有功能的infer.py

将以上所有模块整合为一个独立、无外部依赖的脚本,开箱即用:

# infer.py import cv2 import numpy as np import onnxruntime as ort import sys def preprocess_image(image_path, input_size=800): img = cv2.imread(image_path) if img is None: raise ValueError(f"无法读取图片: {image_path}") h_orig, w_orig = img.shape[:2] scale = input_size / max(h_orig, w_orig) h_new = int(h_orig * scale) w_new = int(w_orig * scale) img_resized = cv2.resize(img, (w_new, h_new)) pad_img = np.zeros((input_size, input_size, 3), dtype=np.uint8) pad_img[(input_size - h_new)//2:(input_size - h_new)//2 + h_new, (input_size - w_new)//2:(input_size - w_new)//2 + w_new] = img_resized img_rgb = cv2.cvtColor(pad_img, cv2.COLOR_BGR2RGB) img_norm = img_rgb.astype(np.float32) / 255.0 img_nchw = np.transpose(img_norm, (2, 0, 1))[np.newaxis, ...] return img_nchw, { 'scale': scale, 'pad_h': (input_size - h_new) // 2, 'pad_w': (input_size - w_new) // 2, 'orig_shape': (h_orig, w_orig), 'resized_shape': (h_new, w_new) } def create_inference_session(model_path): providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] try: session = ort.InferenceSession(model_path, providers=providers) print(f" 已启用GPU加速") except: session = ort.InferenceSession(model_path, providers=['CPUExecutionProvider']) print(f" 回退至CPU模式") return session def postprocess_boxes(pred_boxes, pred_scores, meta, score_threshold=0.2): valid_mask = pred_scores >= score_threshold boxes_valid = pred_boxes[valid_mask] scores_valid = pred_scores[valid_mask] boxes_valid[:, [0, 2]] -= meta['pad_w'] boxes_valid[:, [1, 3]] -= meta['pad_h'] boxes_valid /= meta['scale'] h_orig, w_orig = meta['orig_shape'] boxes_valid[:, [0, 2]] = np.clip(boxes_valid[:, [0, 2]], 0, w_orig) boxes_valid[:, [1, 3]] = np.clip(boxes_valid[:, [1, 3]], 0, h_orig) return boxes_valid.astype(int).tolist(), scores_valid.tolist() def visualize_result(image_path, boxes, scores, output_path="result.jpg"): img = cv2.imread(image_path) for box, score in zip(boxes, scores): x1, y1, x2, y2 = box cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, f"{score:.2f}", (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(output_path, img) print(f" 结果已保存至: {output_path}") if __name__ == "__main__": if len(sys.argv) < 3: print("用法: python infer.py <模型路径> <图片路径> [输入尺寸,默认800]") sys.exit(1) model_path = sys.argv[1] image_path = sys.argv[2] input_size = int(sys.argv[3]) if len(sys.argv) > 3 else 800 print(f" 开始推理: 模型={model_path}, 图片={image_path}, 尺寸={input_size}x{input_size}") # 步骤1: 预处理 input_blob, meta = preprocess_image(image_path, input_size=input_size) # 步骤2: 加载模型 session = create_inference_session(model_path) # 步骤3: 推理 outputs = session.run( output_names=["pred_boxes", "pred_scores"], input_feed={"input": input_blob} ) pred_boxes, pred_scores = outputs[0], outputs[1] # 步骤4: 后处理 boxes, scores = postprocess_boxes(pred_boxes, pred_scores, meta, score_threshold=0.2) # 步骤5: 可视化 output_path = f"result_{input_size}x{input_size}.jpg" visualize_result(image_path, boxes, scores, output_path) print(f" 检测完成!共 {len(boxes)} 个文本区域,平均置信度: {np.mean(scores):.3f}")

5.2 命令行快速使用

将脚本保存为infer.py后,按以下方式调用:

# 使用800x800模型检测test.jpg python infer.py model_800x800.onnx test.jpg # 使用640x640模型(需先导出对应尺寸) python infer.py model_640x640.onnx test.jpg 640 # 查看帮助 python infer.py

输出示例:

开始推理: 模型=model_800x800.onnx, 图片=test.jpg, 尺寸=800x800 已启用GPU加速 结果已保存至: result_800x800.jpg 检测完成!共 8 个文本区域,平均置信度: 0.921

6. 常见问题与调试指南

6.1 检测框严重偏移或消失?

原因:预处理中未正确执行等比缩放+对称填充,或后处理中坐标还原步骤错误(如忘记减去pad或未除以scale)。

解决

  • cv2.imshow分别检查img_resized(缩放后)和pad_img(填充后)是否符合预期;
  • 打印meta中的pad_h/pad_wscale,确认数值合理(如原图1200×800,scale=800/1200≈0.667pad_h=0pad_w=80);
  • 在后处理中打印boxes_valid的中间值,确认其范围是否在[0, input_size]内。

6.2 推理报错InvalidArgument: Input tensor not found

原因input_feed中的键名与模型实际输入名不匹配。

解决

  • 运行print([inp.name for inp in session.get_inputs()]),确认输入名(常见为"input""images""x");
  • input_feed={"input": input_blob}中的"input"替换为实际名称。

6.3 CPU推理速度过慢(>5秒)?

原因onnxruntime默认使用单线程。可通过设置sess_options启用多线程:

sess_options = ort.SessionOptions() sess_options.intra_op_num_threads = 0 # 0表示使用所有物理核心 session = ort.InferenceSession(model_path, sess_options, providers=['CPUExecutionProvider'])

7. 总结:为什么这套方案值得你采用

本文提供的ONNX推理方案,不是一份泛泛而谈的API文档,而是一个经过生产环境验证、与WebUI行为严格对齐的最小可行实现(MVP)。它的价值体现在三个层面:

  • 一致性保障:从预处理、推理到后处理,每一步都与科哥WebUI的逻辑完全一致,确保你在本地脚本中得到的结果,与在浏览器中点击“开始检测”看到的结果完全相同。这种一致性是工程落地的生命线。
  • 零学习成本:无需理解ONNX IR规范、无需配置复杂环境,只需安装三个包、复制粘贴脚本、替换路径,即可获得开箱即用的OCR能力。它把“调用模型”这件事,真正简化为一次函数调用。
  • 灵活可扩展:脚本结构清晰,模块解耦。你可以轻松将postprocess_boxes替换为自己的NMS(非极大值抑制)逻辑,或在visualize_result中集成文本识别(OCR Recognition)模块,构建完整的端到端OCR流水线。

OCR不是炫技的玩具,而是解决真实问题的工具。当你需要在服务器上批量处理数千张发票、在边缘设备上实时检测产线标签、或为内部系统嵌入一个可靠的文本定位能力时,这套简洁、可靠、可验证的ONNX推理方案,就是你最值得信赖的起点。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 4:31:34

开源大模型部署趋势分析:轻量级BERT在实际项目中的应用

开源大模型部署趋势分析&#xff1a;轻量级BERT在实际项目中的应用 1. BERT 智能语义填空服务&#xff1a;让AI理解中文上下文 你有没有遇到过这样的场景&#xff1a;写文章时卡在一个词上&#xff0c;怎么都想不起最贴切的表达&#xff1f;或者读一段文字时发现缺了一个字&a…

作者头像 李华
网站建设 2026/4/18 4:24:48

细节控福音:fft npainting lama小范围瑕疵修复精准到位

细节控福音&#xff1a;fft npainting lama小范围瑕疵修复精准到位 1. 引言&#xff1a;为什么你需要一个精准的图像修复工具&#xff1f; 你有没有遇到过这样的情况&#xff1a;一张珍贵的照片上出现了划痕&#xff0c;或者截图里有个碍眼的水印怎么都去不掉&#xff1f;又或…

作者头像 李华
网站建设 2026/4/17 20:17:32

用Qwen-Image-Layered轻松实现LOGO与背景分离

用Qwen-Image-Layered轻松实现LOGO与背景分离 你有没有遇到过这样的尴尬&#xff1f; 设计团队发来一张带品牌LOGO的宣传图&#xff0c;市场部却突然要求&#xff1a;“把LOGO单独抠出来&#xff0c;换到新海报上”&#xff1b; 或者客户说&#xff1a;“这张产品图背景太杂&a…

作者头像 李华
网站建设 2026/4/18 4:24:37

Glyph推理卡顿?低成本GPU算力适配优化实战案例

Glyph推理卡顿&#xff1f;低成本GPU算力适配优化实战案例 1. 问题缘起&#xff1a;为什么Glyph在4090D上会卡顿&#xff1f; 你刚拉取完Glyph镜像&#xff0c;兴冲冲地在4090D单卡服务器上跑起来&#xff0c;点开网页界面准备测试长文本推理——结果输入框一敲字&#xff0c…

作者头像 李华
网站建设 2026/4/18 4:25:12

BERT模型400MB怎么做到的?轻量架构设计原理深度解析

BERT模型400MB怎么做到的&#xff1f;轻量架构设计原理深度解析 1. BERT 智能语义填空服务&#xff1a;小身材&#xff0c;大智慧 你有没有想过&#xff0c;一个只有400MB的AI模型&#xff0c;居然能准确猜出“床前明月光&#xff0c;疑是地[MASK]霜”中的“上”字&#xff1…

作者头像 李华
网站建设 2026/4/18 4:25:13

不用GPU大户也能玩AI绘图,麦橘超然真香体验

不用GPU大户也能玩AI绘图&#xff0c;麦橘超然真香体验 你是不是也经历过这样的尴尬&#xff1a;看到别人用 Flux 生成的赛博朋克城市、水墨风山水、电影级人像&#xff0c;心痒难耐想上手试试&#xff0c;结果一查显存要求——“推荐 RTX 4090&#xff0c;最低需 24GB VRAM”…

作者头像 李华