尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

用Python和OCR搭建本地音游成绩复盘工具

用Python和OCR搭建本地音游成绩复盘工具 很多舞萌DX玩家看到“明年才能打舞萌了”这句话第一反应大多是无奈机台不在身边、门店搬迁、学业工作排满或者单纯是排不上机。既然短期内没法在线下痛快打与其让手感空白不如把这段时间用来做更值的事——把手头散落的成绩截图整理成一套个人数据系统用OCR识别分数和评级批量归档跑出趋势统计再接一个本地API方便随时查询。这篇文章就围绕这件事展开。我们要做的事情并不复杂用Python搭一个本地“舞萌DX成绩复盘工具”输入是玩家自己的成绩截图输出是结构化数据、统计结果和查询接口。整个方案不需要高配显卡CPU模式就够了支持批量处理截图能通过本地接口服务查询历史成绩数据全部留在本机不会上传到任何第三方平台。对于经常截成绩、想复盘刷分、又不想手动填Excel的玩家来说这套东西可以直接落地。文章会按“能力概览 - 环境准备 - 部署启动 - 功能测试 - API与批量 - 性能观察 - 排错 - 最佳实践”的顺序展开。过程中会给出可以直接复制的代码框架也会注明哪些地方需要按你本机的情况替换。整体思路同样适用于其他音游截图管理不限于舞萌DX。1. 核心能力速览先给结论这个个人工具项目不是一个大模型也不是一个重型应用而是一套本地OCR成绩识别 数据归档 API查询的轻量工具链。核心能力如下。能力项说明项目定位本地音游成绩截图识别与复盘统计工具主要功能成绩截图OCR识别、字段提取、批量归档、统计查询、本地API服务技术选型Python OCR引擎(如RapidOCR/PaddleOCR) SQLite FastAPI硬件要求CPU可运行NVIDIA GPU可选加速显存占用OCR模型通常较小CPU模式下基本不占显存GPU模式以实际模型为准启动方式命令行启动脚本 / API服务接口能力提供成绩查询、批量导入等HTTP接口批量任务支持指定目录批量识别可加日志和失败重试数据存储SQLite本地文件方便导出适合场景个人成绩复盘、刷分规划、群友冲榜活动统计从开发角度看这个方案适合对Python基础、OCR调用、本地API有兴趣的玩家。哪怕你是第一次接触OCR也可以跑通基础流程因为OCR引擎本身已经做了大量封装真正需要写的业务代码并不多。2. 适用场景与使用边界这个工具适合谁适合解决什么问题需要先说清楚。适合玩家在以下场景使用电脑里已经有大量舞萌DX成绩截图想统一归档。想追踪某张谱面从初见到现在达成率的变化趋势。刷分阶段想快速统计最近10次是否在进步。想给群友做一个小范围冲榜数据看板但不方便用在线表单收集隐私信息。想学习OCR怎么和实际业务结合把游戏截图变成结构化数据。不适合什么场景不适合拿去处理别人的成绩截图除非你已获得对方明确授权。不适合上传到公网作为多人服务使用本地工具默认只绑本机地址更稳妥。不包含任何游戏模拟器、未授权ROM或版权谱面资源这个项目只处理玩家自己生成的屏幕截图。合规边界非常重要。成绩截图可能包含游戏昵称、Rating、玩家标识等信息虽然不算特别敏感但从隐私角度数据最好只保留在本地。如果你准备在博客或视频中使用截图建议对昵称和ID做脱敏处理。涉及他人截图时必须先获得授权避免不必要的隐私争议。3. 环境准备与前置条件搭建这套工具不需要多高的硬件配置普通办公电脑即可。建议环境如下。3.1 系统环境Windows 10/11LinuxmacOS均可。Windows下建议安装Visual C Build Tools部分Python依赖需要本地编译。磁盘剩余空间建议5GB以上主要是Python环境和OCR模型占空间。3.2 软件与运行库软件建议版本/说明Python3.9 以上建议 3.10 或 3.11pip随Python安装用于装依赖SQLitePython内置不需要单独安装OCR引擎RapidOCR(ONNX Runtime) 或 PaddleOCR 二选一Web框架FastAPI Uvicorn 或 Flask这里不把依赖版本写死因为OCR引擎更新较快具体以官方文档为准。建议优先选择RapidOCR这类基于ONNX Runtime的方案部署简单CPU推理速度通常够用。3.3 目录结构规划建议先建立一套清晰的目录避免后面数据混乱maimai_analyzer/ ├── screens/ # 存放原始成绩截图 ├── output/ # OCR识别后的JSON结果 ├── data/ # SQLite数据库文件 ├── logs/ # 运行日志 ├── app.py # FastAPI主程序 ├── batch_ocr.py # 批量识别脚本 ├── config.yaml # 配置文件 └── requirements.txt这样设计的好处是原始截图、中间结果、最终数据、日志彼此隔离后续排查问题能快速定位。3.4 端口规划API服务默认建议使用127.0.0.1:8000只在本机访问避免暴露到局域网或公网。如果8000端口被占用启动时改掉即可。4. 安装部署与启动方式4.1 创建虚拟环境打开终端进入项目目录执行python -m venv venv激活虚拟环境Windows:venv\Scripts\activateLinux/macOS:source venv/bin/activate4.2 安装依赖先把依赖写入requirements.txt内容大致如下具体版本以你选择的OCR引擎官方要求为准fastapi uvicorn[standard] opencv-python rapidocr-onnxruntime pyyaml然后安装pip install -r requirements.txt如果选择 PaddleOCR安装命令需要按官方文档调整例如先安装PaddlePaddle再安装PaddleOCR。GPU加速需要额外安装对应CUDA版本的PaddlePaddle这一步比较依赖显卡驱动可以先从CPU版跑通。4.3 编写配置文件创建config.yamlinput_dir: ./screens output_dir: ./output data_db: ./data/maimai.db host: 127.0.0.1 port: 8000 batch_size: 4 timeout: 10说明input_dir是待识别截图目录。output_dir存放每张图的OCRJSON结果。data_db是SQLite数据库路径。batch_size是批量任务并发数CPU机器建议设置2到4不要太高。host固定为本机地址。4.4 启动批量识别脚本以RapidOCR为例先写一个最简单的批量识别脚本batch_ocr.pyimport os import json import time from pathlib import Path import yaml from rapidocr_onnxruntime import RapidOCR config yaml.safe_load(open(config.yaml, encodingutf-8)) engine RapidOCR() input_dir Path(config[input_dir]) output_dir Path(config[output_dir]) output_dir.mkdir(parentsTrue, exist_okTrue) image_paths list(input_dir.glob(*.png)) list(input_dir.glob(*.jpg)) print(f待处理图片数量: {len(image_paths)}) for i, image_path in enumerate(image_paths, 1): start time.time() result, _ engine(str(image_path)) output_file output_dir / f{image_path.stem}.json output_file.write_text(json.dumps(result, ensure_asciiFalse, indent2), encodingutf-8) print(f[{i}/{len(image_paths)}] {image_path.name} 处理完成耗时 {time.time() - start:.2f}s)运行python batch_ocr.py这是通用模板。如果你用的OCR引擎不是RapidOCR需要把engine(str(image_path))替换为对应库的调用方式。第一次运行会自动下载ONNX模型需要保证网络通畅模型下载完成后即可离线使用。4.5 启动API服务在app.py中写一个最小可用的FastAPI服务from fastapi import FastAPI import uvicorn app FastAPI(titleMaimai Score Analyzer) app.get(/health) def health(): return {status: ok} if __name__ __main__: uvicorn.run(app, host127.0.0.1, port8000)启动python app.py浏览器访问http://127.0.0.1:8000/health如果看到{status:ok}说明服务正常。下一步再往里加成绩查询和批量导入接口。5. 功能测试与效果验证部署完成之后进入功能验证阶段。先不要直接上全量批量任务按下面顺序跑一遍。5.1 单张截图OCR测试测试目的确认OCR引擎能识别成绩截图中的文字内容。操作步骤把一张成绩截图放到screens目录例如lv12_pass.png。运行上面的batch_ocr.py。打开output/lv12_pass.json查看输出内容。预期结果JSON里应包含识别出的文本块和坐标信息字段数量取决于成绩截图上的文字。判断成功标准是至少能正确识别出歌曲名、分数、达成率、评级中的两项。常见失败原因是截图分辨率和字体差异这时需要先做图像预处理再识别。5.2 结构化字段提取OCR的原始结果是一堆文字框还不是可以直接统计的结构化数据。需要再加一层后处理从文本框中提取关键字段。import re def extract_fields(ocr_result): 从OCR结果中提取关键字段。实际规则需要根据你的成绩截图调整。 text .join([item[1] for item in ocr_result]) fields {} score_match re.search(r(\d{6,7}), text) if score_match: fields[score] int(score_match.group(1)) if SSS in text: fields[rating] SSS elif SSS in text: fields[rating] SSS elif SS in text: fields[rating] SS elif S in text: fields[rating] S return fields这个函数是示例你需要根据实际截图布局调整正则和评级判断顺序。测试方法先用3到5张不同难度、不同评级的截图跑一遍确认字段提取准确率。5.3 批量目录测试确认单张没问题后把screens目录扩充到几十张截图再次运行python batch_ocr.py重点观察是否全部处理完成。是否有某张图识别结果为空。处理速度是否稳定。中途是否出现内存增长异常。批量任务建议拆成小批次运行比如每次处理50张处理完查一次数据完整性再处理下一批。5.4 数据入库与趋势查看OCR结束后把提取的字段写入SQLiteimport sqlite3 conn sqlite3.connect(data/maimai.db) conn.execute( CREATE TABLE IF NOT EXISTS scores ( id INTEGER PRIMARY KEY AUTOINCREMENT, song_name TEXT, score INTEGER, rating TEXT, achievement REAL, created_at TEXT DEFAULT CURRENT_TIMESTAMP ) ) conn.commit() conn.close()入库后可以用SQL查平均分、最高分、最近一周成绩变化趋势。到这里一份完整的本地成绩库就算建成了。6. 接口 API 与批量任务工具跑通之后建议把查询能力接口化这样以后不管写脚本统计还是做一个小页面展示都可以直接调用。6.1 增加成绩查询接口在app.py中扩展FastAPI代码from fastapi import FastAPI, HTTPException from pydantic import BaseModel import sqlite3 import uvicorn app FastAPI(titleMaimai Score Analyzer) DB_PATH data/maimai.db class ScoreIn(BaseModel): song_name: str score: int rating: str achievement: float 0.0 def get_db(): return sqlite3.connect(DB_PATH) app.get(/health) def health(): return {status: ok} app.post(/scores) def add_score(item: ScoreIn): conn get_db() try: conn.execute( INSERT INTO scores (song_name, score, rating, achievement) VALUES (?, ?, ?, ?), (item.song_name, item.score, item.rating, item.achievement), ) conn.commit() finally: conn.close() return {status: ok, data: item} app.get(/scores) def list_scores(limit: int 20): conn get_db() try: rows conn.execute(SELECT song_name, score, rating, achievement FROM scores ORDER BY score DESC LIMIT ?, (limit,)).fetchall() return {status: ok, count: len(rows), data: rows} finally: conn.close() if __name__ __main__: uvicorn.run(app, host127.0.0.1, port8000)6.2 使用curl测试接口服务启动后打开新终端执行curl -X POST http://127.0.0.1:8000/scores \ -H Content-Type: application/json \ -d {song_name:Test Song,score:1000000,rating:SSS,achievement:100.5}返回{status: ok, data: {song_name: Test Song, score: 1000000, rating: SSS, achievement: 100.5}}再查询curl http://127.0.0.1:8000/scores?limit56.3 Python调用示例在实际项目中可以用Python批量写入OCR解析后的结果import requests url http://127.0.0.1:8000/scores payload { song_name: Grievous Lady, score: 1002500, rating: SSS, achievement: 100.25, } response requests.post(url, jsonpayload, timeout10) print(response.json())6.4 批量导入队列设计如果一次导入几千条成绩不建议每条都同步发HTTP请求。更稳的做法是OCR批量识别结束后把所有解析结果先写JSON文件。按批次读取JSON每批50条逐批POST到本地API。每批结束后标记进度失败自动重试3次仍失败则写入错误日志。伪代码框架import json import time from pathlib import Path import requests API_URL http://127.0.0.1:8000/scores output_dir Path(./output) for json_file in sorted(output_dir.glob(*.json)): data json.loads(json_file.read_text(encodingutf-8)) # 这里需要把OCR原始结果转成ScoreIn字段 record {song_name: Unknown, score: 0, rating: , achievement: 0.0} for attempt in range(3): try: resp requests.post(API_URL, jsonrecord, timeout10) if resp.status_code 200: break except Exception as exc: print(f{json_file.name} 第{attempt1}次失败: {exc}) time.sleep(1)这个框架重点在“分批 失败重试 日志”实际字段映射需要根据你的OCR输出调整。7. 资源占用与性能观察资源占用是很多玩家关心的问题。这套工具的负载大头在OCR引擎而不是API服务。观察方法很简单CPU模式打开任务管理器看Python进程的CPU占用和内存占用。GPU模式在终端运行nvidia-smi -l 1观察显存使用。批量任务运行时留意磁盘读写是否成为瓶颈。通用规律如下OCR引擎在CPU模式下识别单张成绩截图的时间通常在秒级具体取决于图片分辨率、文字数量和模型大小。GPU模式下单张识别速度可能会更快但不是必须。显存占用取决于模型规格实际占用需要以本机测试为准。批量任务并发数越高内存占用越高。建议先用小并发跑通再根据内存情况逐步调大。图片分辨率过大时可以缩放到合适尺寸再识别速度会明显提升。如果同时跑API服务和批量识别注意端口资源与内存互相挤占。降低资源占用的方法先压缩截图把2K截图缩放到宽度1600以内识别速度和稳定性往往更好。控制批大小CPU机器batch_size建议2到4。关闭无用的后台进程尤其是浏览器的大标签页。如果长期批量跑建议定时监控日志防止任务卡死。8. 常见问题与排查方法问题现象可能原因排查方式解决方案OCR识别结果为空图片格式不支持、分辨率过低、截图内容模糊检查图片能否正常打开查看日志放大截图、转成PNG、先做图像预处理识别出来乱码或错字字体特殊、文字倾斜、模型识别偏差查看单张识别JSON确认是哪一步错了用截图裁剪局部测试调整预处理参数字段提取不全后处理正则与实际截图格式不匹配打印OCR原始结果根据实际截图修改正则规则接口返回500地址或数据库读写不匹配查看FastAPI控制台日志检查SQLite路径、字段类型启动时端口被占用8000端口被其他进程占用Windows netstat -anofindstr 8000Linuxlsof -i:8000批量任务卡住单张OCR卡住或网络模型下载失败先单独测试一张图片给OCR调用加超时重试机制数据入库数量不对batch脚本与API重复插入或漏插对比JSON文件数量和数据库条数加日志记录每批插入结果模型文件缺失首次运行未完成模型下载检查模型缓存目录手动下载模型文件并放入指定目录出现问题时最有效的方法是缩小问题范围。先跑单张确认OCR是否正常再跑批量确认是某一张图片的问题还是整体流程问题最后再查API和数据库层。9. 最佳实践与使用建议工具能用和工具好用是两码事。下面几条建议来自日常折腾这类脚本最容易踩坑的地方。第一次跑通流程时不要直接全量导入。选3张代表性截图走完“识别 提取 入库 查询”全流程确认无误后再处理剩余截图。原始截图不要删。OCR识别结果可以被重新解析但原始截图中包含的图像信息无法从文本结果还原。建议按月份归档到不同文件夹。输出中间结果要有独立目录。JSON文件、数据库、日志分开存放。排查问题时能快速定位是OCR阶段还是入库阶段丢失数据。API服务默认只绑定127.0.0.1不要改成0.0.0.0除非你把安全访问控制做好了。数据留在本机是对自己隐私负责。涉及游戏截图、别人成绩、玩家昵称时发布到公开平台前做好脱敏处理。不要用他人数据做展示除非获得授权。关于游戏本身不要在工具里集成任何未授权模拟器、ROM、版权谱面资源。你的复盘工具只处理玩家自己生成的截图这样既安全又合规。批量任务一定要有日志。没有日志的批量任务就像没有仪表盘的驾驶出了问题很难定位。至少记录哪张图开始、是否成功、耗时多少、失败原因是什么。10. 总结与下一步回到开头那句“明年才能打舞萌了”。等待期最值得做的事情不是干等而是把已有数据盘活。这套本地成绩复盘工具的思路很简单截图 - OCR - 结构化数据 - SQLite - API查询。它能让你在无法上机的日子里依然能看到自己水平变化的轨迹。如果是从零开始建议最先验证单张截图识别再跑批量。最容易踩的坑是OCR后处理规则和你的实际截图不匹配这需要用几张真实截图去调。等数据积累得足够多还可以继续扩展方向做一个简单的趋势图页面接入语音提示刷分目标或者把群友的成绩截图汇总成一张排行榜。工具本身只是起点想怎么用取决于你希望从数据里看到什么。建议先把这套流程搭起来备份好自己的截图固定一个本地目录跑通第一批数据。等到下次真的能上机你打开数据库就能看到从一个分数到另一个分数之间到底走了多远。
返回列表