MeterDetRead 是一个端到端的深度学习仪表读数识别系统。它结合了 YOLO26 目标检测定位仪表区域,以及 ResNet34-OCR 模型配合 CTC(连接时序分类)解码识别数值读数。系统覆盖完整的机器学习生命周期:数据标注、数据集生成、模型训练、ONNX 导出、命令行推理以及基于 Docker 的生产级部署。
┌─────────────────────┐
│ 输入图片 │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ YOLO26 检测器 │
│ (仪表区域定位) │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ 裁剪的仪表区域 │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ ResNetOCR + CTC │
│ (数字识别) │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ 识别结果 │
│ 如 "1234.56" │
└─────────────────────┘
-
两阶段识别流程 — YOLO26 检测仪表区域,ResNet34-OCR 解析数值读数。模块化设计,职责清晰,各组件可独立替换。
-
双引擎推理 — 支持 PyTorch 原生推理与 ONNX Runtime 高性能推理,两种后端共用统一的命令行接口,无需修改代码即可切换。
-
完整机器学习管线 — 从数据标注到生产部署一站式覆盖:GUI 标注工具 → 数据集生成 → 模型训练 → ONNX 导出 → API 服务。所有步骤脚本化、可复现。
-
图形化标注工具 — 基于 PyQt6 的桌面标注应用,支持矩形框绘制与编辑、标注/浏览双模式切换、数据完整性校验、一键导出训练格式。
-
生产级 API 服务 — FastAPI + ONNX Runtime 推理后端,多阶段 Docker 镜像构建,健康检查端点,支持 JPEG / PNG / BMP / WEBP 多格式图片,可通过环境变量配置子路径部署。
-
强化 OCR 架构 — ResNet34 骨干网络,集成 ECA 通道注意力机制、注意力池化、多层卷积 CTC 头、余弦预热学习率调度,以及亮度、对比度、旋转、噪声、模糊、Cutout 等数据增强策略。
-
配置驱动设计 — 训练、推理、导出等所有阶段的参数统一通过 YAML 配置文件管理,确保各环节参数一致性。
- Python ≥ 3.12
- CUDA ≥ 11.8(可选,用于 GPU 加速训练)
- uv 包管理器
# 克隆仓库
git clone https://github.com/noimank/MeterDetRead.git
cd MeterDetRead
# 安装依赖
uv sync
# 激活虚拟环境
source .venv/bin/activate # Linux / macOS
.venv\Scripts\activate # Windows训练检测模型前需下载 YOLO26 预训练权重:
mkdir -p data/yolo_weight
# 从 Ultralytics 下载 yolo26n.pt 并放入 data/yolo_weight/ 目录# 将原始仪表图片放入 data/raw/ 目录
cp /path/to/meter/images/*.jpg data/raw/
# 启动标注工具
python annotator_gui_app.py在图形界面中框选仪表区域并输入对应的读数值,标注数据会自动保存到 data/annotated/ 目录。
python split_dataset.py --train-ratio 0.8 --val-ratio 0.1 --test-ratio 0.1生成 YOLO 格式的检测标签以及用于 OCR 训练的裁剪区域图片。
# 训练检测模型
python train_det.py --epochs 300 --batch 16
# 训练识别模型
python train_resnet_ocr.py# PyTorch 推理(默认)
python infer.py --source path/to/images
# ONNX 推理(需先导出,速度更快)
python infer.py --source path/to/images --use-onnx# 导出 ONNX 模型
python export_onnx.py
# 构建并运行 Docker 容器
docker build -t meter-reader:latest .
docker run -d --name meter-reader -p 8000:8000 meter-reader:latest
# 测试接口
curl -X POST "http://localhost:8000/api/detect_and_read" -F "file=@meter.jpg"| 步骤 | 脚本 | 输入 | 输出 |
|---|---|---|---|
| 标注 | annotator_gui_app.py |
data/raw/ |
data/annotated/(JSON 格式) |
| 数据集切分 | split_dataset.py |
data/annotated/ |
data/datasets/(YOLO + OCR 格式) |
{
"image": "meter_001.jpg",
"width": 1920,
"height": 1080,
"annotations": [
{ "bbox": [100, 200, 300, 400], "value": "123.45" }
]
}bbox:边界框坐标[x1, y1, x2, y2](绝对像素坐标)value:仪表的真实读数值
内置的 PyQt6 标注工具支持两种工作模式:
| 模式 | 快捷键 | 说明 |
|---|---|---|
| 标注模式 | Ctrl+1 |
对 data/raw/ 中的新图片进行标注,保存后自动移至 data/annotated/ |
| 浏览模式 | Ctrl+2 |
浏览和编辑 data/annotated/ 中已有的标注 |
常用快捷键:Ctrl+S 保存,← / → 切换图片,鼠标拖拽绘制标注框,点击选中后可编辑移动。
训练 YOLO26 单类别(仪表)目标检测模型,所有参数通过 configs/det/yolo.yaml 配置管理。
python train_det.py --config configs/det/yolo.yaml --epochs 300 --batch 16 --lr 0.01| 参数 | 默认值 | 说明 |
|---|---|---|
--config |
configs/det/yolo.yaml |
配置文件路径 |
--epochs |
配置文件中的值 | 训练轮数 |
--batch |
配置文件中的值 | 批次大小 |
--lr |
配置文件中的值 | 学习率 |
训练 ResNet34-OCR 模型,采用 CTC Loss 进行端到端序列识别。支持断点续训、混合精度训练、余弦预热学习率调度及可配置的数据增强策略。
python train_resnet_ocr.py --config configs/rec/resnet_ocr.yaml统一推理命令行工具,同时支持 PyTorch 和 ONNX 两种后端:
# 基础用法
python infer.py --source data/raw
# 完整参数
python infer.py \
--det-model data/outputs/det/exp/weights/best.pt \
--rec-model data/outputs/rec_resnet/best_model.pt \
--source data/test/images \
--output data/results \
--crops-dir data/crops \
--use-onnx| 参数 | 默认值 | 说明 |
|---|---|---|
--source |
data/datasets/test/images |
输入图片路径(目录或单文件) |
--det-model |
data/outputs/det/exp/weights/best.pt |
检测模型路径 |
--rec-model |
data/outputs/rec_resnet/best_model.pt |
识别模型路径 |
--use-onnx |
false |
启用 ONNX Runtime 推理 |
--crops-dir |
null |
保存裁剪仪表区域到指定目录 |
--output |
data/outputs/infer |
结果输出目录 |
# 导出全部模型
python export_onnx.py
# 选择性导出
python export_onnx.py --det-only
python export_onnx.py --rec-only --output onnx_models导出产物:yolo26_det.onnx 和 resnet_ocr.onnx
服务提供以下接口:
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/health |
健康检查,返回服务及模型加载状态 |
POST |
/api/detect |
检测图片中的仪表边界框 |
POST |
/api/read |
读取已裁剪仪表图片中的数值 |
POST |
/api/detect_and_read |
一体化接口:检测并读取仪表数值 |
import requests
url = "http://localhost:8000/api/detect_and_read"
with open("meter.jpg", "rb") as f:
response = requests.post(url, files={"file": f})
result = response.json()
# {
# "results": [
# {"bbox": [100, 200, 300, 400], "confidence": 0.95, "reading": "123.45"}
# ],
# "count": 1,
# "inference_time_ms": {"total": 45.2, "detection": 20.1, "reading": 25.1}
# }curl -X POST "http://localhost:8000/api/detect_and_read" -F "file=@meter.jpg"完整的接口文档、错误码说明及多语言示例(JavaScript、Python、cURL)详见 API 文档。
# 拉取并运行已发布的镜像
docker run -d --name meter-reader -p 8000:8000 noimankdocker/meter-reader:latest
# 打开浏览器访问 http://localhost:8000 即可使用 Web 演示界面
# 或通过 API 测试
curl -X POST "http://localhost:8000/api/detect_and_read" -F "file=@meter.jpg"# 构建镜像
docker build -t meter-reader:latest .
# 运行容器
docker run -d --name meter-reader -p 8000:8000 meter-reader:latest
# 子路径部署(适用于反向代理场景)
docker run -d --name meter-reader \
-p 8000:8000 \
-e BASE_URL_PREFIX=meter-reader \
meter-reader:latest镜像采用多阶段构建优化体积。容器内置健康检查(30 秒间隔),确保服务可用性。
MeterDetRead/
├── src/meterdetread/ # 核心 Python 包
│ ├── annotator/ # PyQt6 标注工具
│ │ ├── ui/ # 主窗口与 UI 组件
│ │ ├── widgets/ # 画布、图片列表、标注面板
│ │ ├── managers/ # 标注状态管理与导出逻辑
│ │ └── validators/ # 数据完整性校验
│ ├── models/ # 模型实现
│ │ ├── resnet_ocr.py # ResNet34-OCR(含 ECA 注意力)
│ │ ├── attention_modules.py # 注意力池化等模块
│ │ └── loss.py # CTC Loss 与数据集类
│ └── config.py # 统一配置管理
├── configs/ # YAML 配置文件
│ ├── det/yolo.yaml # 检测模型配置
│ └── rec/resnet_ocr.yaml # 识别模型配置
├── serve/ # 推理 API 服务
│ ├── api.py # FastAPI 应用
│ └── static/index.html # Web 演示界面
├── train_det.py # 检测模型训练脚本
├── train_resnet_ocr.py # 识别模型训练脚本
├── infer.py # 统一推理命令行工具
├── export_onnx.py # ONNX 模型导出脚本
├── annotator_gui_app.py # 标注工具入口
├── split_dataset.py # 数据集生成脚本
├── Dockerfile # 多阶段 Docker 构建文件
└── pyproject.toml # 项目元数据与依赖声明
Model:
name: yolo26n
weights: data/yolo_weight/yolo26n.pt
Dataset:
config: data/datasets/data.yaml
nc: 1
names: ['meter']
Inference:
imgsz: 640
conf_threshold: 0.25
iou_threshold: 0.45
Training:
epochs: 1000
batch: 16
optimizer: SGD
lr0: 0.01
amp: true
Export:
opset: 18
simplify: true
dynamic: false
half: falseGlobal:
character: "0123456789."
img_h: 128
img_w: 256
Architecture:
name: ResNetOCR
backbone:
name: ResNet34
pretrained: true
use_eca: true
encoder:
seq_len: 32
use_attention_pooling: true
head:
name: CTCHead
hidden_dim: 128
dropout: 0.3
Training:
batch_size: 16
num_workers: 0
amp: false
DataAugmentation:
enabled: true
brightness_prob: 0.5
contrast_prob: 0.5
rotation_prob: 0.3
noise_prob: 0.3
blur_prob: 0.2
cutout_prob: 0.1Q: 训练时出现 CUDA 显存不足?
减小配置文件中的 batch_size,或启用 AMP 混合精度训练(amp: true)。
Q: Windows 下多进程数据加载报错?
将识别模型配置中的 num_workers 设为 0(默认已设置为 0)。
Q: ONNX 推理结果与 PyTorch 不一致?
检查配置文件中的 imgsz、img_h、img_w 是否与训练时完全一致。
Q: 检测不到仪表?
尝试降低 configs/det/yolo.yaml 中的 conf_threshold(如从 0.25 降至 0.15),或者扩充训练数据覆盖更多场景。
欢迎社区贡献。请遵循以下流程:
- Fork 本仓库
- 创建功能分支 (
git checkout -b feature/your-feature) - 实现你的改动
- 运行代码检查 (
ruff check . && black .) - 使用 Conventional Commits 规范提交 (
git commit -m 'feat: add your feature') - 推送分支并创建 Pull Request
本项目基于 MIT 许可证开源。详见 LICENSE 文件。
- Ultralytics YOLO — 目标检测框架
- ONNX Runtime — 跨平台推理引擎
- FastAPI — Web API 框架
作者: noimank | 邮箱: noimank@163.com
