# ocr_meter **Repository Path**: pf121x/ocr_meter ## Basic Information - **Project Name**: ocr_meter - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-24 - **Last Updated**: 2026-09-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ocr_meter.py 使用说明 仪表"总量"读数单张识别 CLI,含历史记录 + 智能验证 + 进位自动适应。 --- ## 一、功能概述 | 能力 | 说明 | |---|---| | 单张识别 | 传入图片 + 表名,OCR 识别总量读数 | | 多表支持 | 文件名剥离末尾 13 位时间戳得表名,按表名独立配置/历史 | | 小数位配置 | `tables_config.json` 初始化各表小数位;OCR 带点时以 OCR 为准,漏点时按配置补点 | | 进位/移位 | OCR 小数位 ≠ 配置小数位 → `carry_detected=true`;可 `--auto-update-config` 自动更新配置 | | 智能验证 | 每表存最近 10 次记录,算平均使用量,预测当前值,判定本次可靠 | | 输出 | stdout 一行 JSON,便于程序解析;模型日志走 stderr | --- ## ⚡ 命令速查(最常用,按需选择) > 三种使用方式:**源码运行** → **打包成 exe** → **exe 直接运行(免 Python 环境)** ### ① 源码方式运行(本机已安装 Python 环境) ```bash python ocr_meter.py "t\guolu40t1784574052023.png" guolu40t ``` ### ② 打包成 exe(在装有 Python 的开发机上执行一次,约 9 分钟) ```bash # 方式 A:双击运行(自动完成 清理 → 打包 → 拷贝配置/历史) build.bat # 方式 B:命令行手动执行 pyinstaller ocr_meter.spec --noconfirm ``` - 产物目录:`dist\ocr_meter\`(约 1.7 GB,含模型 + 全部运行依赖) - 打包配置说明见 [ocr_meter.spec](ocr_meter.spec),运行时补丁见 [runtime_hook.py](runtime_hook.py) ### ③ 运行打包好的 exe(目标机器无需安装 Python,拷过去就能用) ```bash cd dist\ocr_meter ocr_meter.exe "..\..\t\guolu40t1784574052023.png" guolu40t ``` **部署方法**:把整个 `dist\ocr_meter\` 文件夹拷贝到任意 Windows 机器,双击 `ocr_meter.exe` 即可运行,无需安装 Python 或任何依赖。包内已含 `tables_config.json` 与 `history\` 历史记录。 --- ## 二、环境依赖 - Python 3.13+ - 核心依赖:`paddleocr`、`paddlex`、`paddlepaddle`、`onnxruntime`、`opencv-contrib-python`、`numpy`、`Pillow` 实测版本(2026-09): | 包 | 版本 | |---|---| | Python | 3.13.5 | | paddleocr | 3.7.0 | | paddlex | 3.7.2 | | paddlepaddle | 3.3.1 | | onnxruntime | 1.30.0 | | opencv-contrib-python | 4.10.0 | 安装: ```bash pip install paddleocr paddlex paddlepaddle onnxruntime opencv-contrib-python numpy pillow ``` **重要**:必须用 onnxruntime 后端(paddlepaddle 3.x 在 CPU 上走 PIR+OneDNN 会崩),脚本内已固定 `engine="onnxruntime"`。 --- ## 三、快速开始 ```bash # 基本调用 python ocr_meter.py "图片路径" 表名 # 示例(使用项目自带 t\ 样例图) python ocr_meter.py "t\guolu40t1784574052023.png" guolu40t # 指定时间戳(不依赖文件名提取) python ocr_meter.py "图片路径" 表名 --ts 1784574052023 ``` 输出(stdout 一行 JSON): ```json {"ok":true,"table":"guolu40t","image":"...","ts":1784574052023,"value":"30239876.98","score":0.9997,"decimal_len":2,"source":"原始","carry_detected":false,"reliable":true,"predicted":null,"avg_usage_per_h":0,"deviation":0,"history_count":1,"history_written":true,"note":"无历史记录,信任OCR"} ``` 程序里调用: ```python import subprocess, json r = subprocess.run(["python","ocr_meter.py","x.png","guolu40t"], capture_output=True, text=True, cwd=r"e:\test") data = json.loads(r.stdout) # stdout 只有这一行 JSON print(data["value"], data["reliable"]) ``` --- ## 四、命令行参数 | 参数 | 必填 | 默认 | 说明 | |---|---|---|---| | `image` | 是 | - | 图片路径 | | `table` | 是 | - | 表名(查配置小数位 + 历史记录) | | `--config` | 否 | 脚本同目录 `tables_config.json` | 配置文件路径 | | `--history-dir` | 否 | 脚本同目录 `history/` | 历史记录目录 | | `--max-tries` | 否 | 3 | OCR 最多重跑次数(漏点时多重跑取带点版本) | | `--auto-update-config` | 否 | 关 | 检测到进位后自动把新小数位写回配置 | | `--ts` | 否 | - | 时间戳(毫秒),优先使用;未传则从文件名提取 13 位时间戳 | | `--no-write-history` | 否 | 关 | 不把本次结果写入历史(默认会写) | --- ## 五、输出 JSON 字段 | 字段 | 类型 | 说明 | |---|---|---| | `ok` | bool | 是否识别到读数 | | `table` | str | 传入的表名 | | `image` | str | 图片路径 | | `ts` | int/null | 13 位毫秒时间戳(`--ts` 传入或从文件名提取) | | `value` | str | 总量读数(字符串,保留原始小数位) | | `score` | float | OCR 置信度 | | `decimal_len` | int | 小数位数 | | `digits` | int/null | 仪表数字总位数(进位校验用,null 表示未配置不校验) | | `source` | str | 来源:`原始` / `补点(原xxx)` / `无点未补(待定)` / `失败` | | `carry_detected` | bool | 是否检测到进位/小数点移位 | | `reliable` | bool | 智能验证是否可靠 | | `predicted` | float/null | 预测应有读数(无历史时 null) | | `avg_usage_per_h` | float | 平均使用量 m³/h(基于历史) | | `deviation` | float/null | 实际值与预测值的偏差 | | `history_count` | int | 该表当前历史记录条数(封顶 10) | | `history_written` | bool | 本次是否写入历史(仅可靠才写) | | `note` | str | 备注/异常说明 | **判定逻辑**: - `ok=false` → OCR 没识别到数字(`note` 说明原因) - `ok=true` 但 `reliable=false` → 识别到值但智能验证不通过(读数下降/偏差过大),需人工复核 - `ok=true` 且 `reliable=true` → 正常,已自动写入历史 --- ## 六、配置文件 tables_config.json 初始化各表的小数位数和数字总位数。格式: ```json { "_说明": "表配置;下划线开头的键会被忽略", "guolu40t": {"decimals": 2, "digits": 10}, "20tguolu": {"decimals": 3, "digits": 10}, "jinglian1": {"decimals": 3, "digits": 10}, "jinglian2": {"decimals": 4, "digits": 10} } ``` - 每项为对象:`decimals` = 小数位数(漏点补点用),`digits` = 数字总位数(进位校验用,整数位+小数位应=digits) - 兼容旧格式:`"guolu40t": 2`(仅小数位,digits 为 null 不校验总位数) - 下划线 `_` 开头的键是注释,不会被当作配置 - 新表首次识别:OCR 带点用 OCR 小数位,漏点无法补(`source=无点未补(待定)`),需手动加配置或等下次带点识别后用 `--auto-update-config` 写入 --- ## 七、历史记录与智能验证 ### 历史文件 - 路径:`history/<表名>.json` - 每表独立,保留最近 10 条(滚动覆盖) - 字段:`ts` / `value` / `score` / `decimal_len` / `source` / `carry_detected` ### 智能验证流程 1. **首条无历史** → 强制可靠,写入历史(建立基线) 2. **平均使用量**:用历史首尾算 `avg_usage_per_h = (末值 - 首值) / 时间差小时` 3. **预测值**:`predicted = 上一可靠值 + avg_usage × 时间差` 4. **单调性**:总量应递增,下降即不可靠(除非进位) 5. **偏差判定**: - 有用量:`允许偏差 = max(平均用量×Δt×2, 预测值×10%)` - 表未走字:`允许偏差 = max(预测值×5%, 10)` - 实际偏差 ≤ 允许偏差 → 可靠 6. **历史纯净**:只有 `reliable=true` 才写入历史,异常值不污染基线 ### 进位/小数点移位 仪表显示窗口固定为 **10 位数字 + 1 个小数点**。小数点位置随走字移动:低位数字轮走到 9 再回 0 时向高位进 1,整数位数增加、小数位数相应减少。 - 判定:OCR 小数位 < 配置小数位,且 `新值 ≈ 旧值 × 10^k`(k=位数差,容差 10%)→ 正常进位,可靠 - 原理:整数位 +k 位 = 小数位 -k 位 = 数值 ×10^k(十进制进位) - 总位数校验:进位后整数位+小数位应 = 配置 `digits`(不变)。若新值实际总位数 ≠ digits,`note` 追加"总位数X≠配置Y,需复核"提示(单张识别和智能验证两处均校验,不影响 reliable 判定,仅提示人工复核) - 示例:配置 3 位 → OCR 识别 2 位,旧值 1234.567 → 新值 12345.6(×10)→ 正常进位 --- ## 八、批量识别脚本 extract_total.py 多表通用批量识别:扫描指定目录下全部图片,自动按表名分组,按时间戳排序识别并做单调性校验。 ```bash # 识别指定目录(参数=图片目录) python extract_total.py "t" # 不传参数则使用脚本内默认目录 python extract_total.py ``` 特性: - 自动从文件名剥离 13 位时间戳得到表名,无需硬编码表名/小数位 - 漏点自动重跑取带点版本,仍漏点则按该表小数位补点 - 数值带定位:先找"总量"标签,再取同行右侧数字框 输出: - 控制台:每张图实时输出候选数 / 是否带点 - 报告文件 `report.txt`:按表分组的逐张明细(读数、置信度、来源、单调性告警)+ 汇总统计 > `extract_total.py` 与主程序 `ocr_meter.py` 相互独立:前者侧重批量出清单,后者侧重单张识别 + 历史智能验证。 --- ## 九、文件结构 ``` e:\test\ ├── ocr_meter.py # 单张识别 CLI(主程序) ├── extract_total.py # 批量识别脚本(多表通用版) ├── tables_config.json # 表小数位/总位数配置 ├── ocr_meter.spec # PyInstaller 打包配置 ├── runtime_hook.py # 运行时 hook(旁路 paddlex 依赖检查) ├── build.bat # 一键打包脚本 ├── README.md │ ├── t\ # 样例测试图(4 表共 32 张) │ ├── build\ # PyInstaller 构建缓存(增量重建用) │ └── dist\ # 打包产物 └── ocr_meter\ ├── ocr_meter.exe # 可执行文件 ├── tables_config.json ├── history\ # 历史记录(4 个表 JSON) └── _internal\ # 运行依赖 + ONNX 模型(约 1.7 GB) ``` --- ## 十、文件名约定 图片文件名 = **表名 + 13 位毫秒时间戳**(+ 可选 `-N` 副本后缀) | 文件名 | 表名 | 时间戳 | |---|---|---| | `guolu40t1747517208048.png` | guolu40t | 1747517208048 | | `jinglian11790130645219-1.png` | jinglian1 | 1790130645219 | 表名可含数字(如 `guolu40t` 的 40),程序只剥离末尾连续 13 位时间戳。 **时间戳也可通过 `--ts` 参数显式传入**,此时不依赖文件名提取,适用于文件名不含时间戳或需覆盖的场景。 --- ## 十一、常见问题 **Q: OCR 识别失败(ok=false)怎么办?** A: 多为 OCR 引擎未检测到数字区域。可尝试:提高图片清晰度、调整拍照角度、增大 `--max-tries`。 **Q: 读数不可靠(reliable=false)但 OCR 置信度高?** A: 智能验证拦截了异常(读数下降或偏差过大)。多为 OCR 把某位数字识别错。查 `note` 字段看具体原因,人工复核该图。 **Q: 新表首次使用如何配置小数位?** A: 三种方式: 1. 手动写入 `tables_config.json` 2. 先让 OCR 识别带点版本(自动得小数位) 3. 用 `--auto-update-config` 检测到带点后自动写入配置 **Q: 进位后小数位变了,配置要手动改吗?** A: 加 `--auto-update-config` 参数,检测到进位后自动把新小数位写回配置,长期运行配置自动跟随表的实际进位。 **Q: 如何在没有 Python 的电脑上使用?** A: 在开发机运行 `build.bat` 完成打包,然后把整个 `dist\ocr_meter\` 文件夹拷到目标电脑,双击 `ocr_meter.exe` 即可,无需安装任何环境。 **Q: 打包后运行报"pipeline (OCR) does not exist"或依赖错误?** A: 打包配置已内置处理:[ocr_meter.spec](ocr_meter.spec) 会收集 paddlex 配置文件、paddle 动态库和包元数据,[runtime_hook.py](runtime_hook.py) 旁路额外依赖检查。请确认使用的是当前最新的 spec 重新打包。