# OCR Data - 视频字幕提取与识别系统 ## 项目简介 本项目是一个自动化视频字幕提取系统,通过视频抽帧、OCR 文字识别、音频语音识别等技术,从视频中提取硬字幕并生成 SRT 字幕文件。支持多线程批量处理,并与腾讯云 COS 对象存储集成(上传/下载)。 OCR 主力来自内部 OCR 服务(Tencent Youtu,封装为 `tencentcloud_ocr_api`);Whisper 仅做辅助校验(识别首尾音频过滤片头片尾台标、与 OCR 文本做拼音匹配),不是字幕文字的主要来源,因此 Whisper 模型大小对最终字幕质量影响有限。 ## 核心功能 - **视频抽帧**:用 FFmpeg `fps` 滤镜单次顺序解码,按固定频率抽帧(默认每秒 3 帧) - **字幕区域检测**:通过 OCR 自动定位字幕区域,识别/过滤水印 - **图片拼接优化**:将多帧字幕区域裁剪后拼接为大图,大幅减少 OCR 调用次数 - **并发 OCR**:getsrt 阶段对拼接图/单独帧并发调用 OCR(`subtitle.ocr_workers` 控制并发数) - **音频辅助校验**:用 Whisper 提取首尾音频文字,与 OCR 结果做拼音匹配 - **SRT 字幕生成**:合并、去重(处理多种 OCR 差异变体),生成标准 SRT - **批量处理**:`ThreadPoolExecutor` 多视频并发;日志/计时按线程隔离 - **运行统计**:每个视频的起止时间、各阶段耗时、图片处理数量写入 `数据.jsonl` ## 项目结构 ``` ocr_data/ ├── main.py # 主入口,批量任务调度 ├── rerun_srt.py # 复用已有OCR数据重生成SRT(调试getsrt用,不重抽帧) ├── requirements.txt # Python 依赖 ├── coscli.exe / coscli-linux-amd64 # 腾讯云 COS CLI 工具 ├── config/ │ ├── config.json # 配置文件(OCR密钥、抽帧参数、模型、并发等) │ └── config_utils.py # 配置管理器(单例) ├── tool/ │ ├── process.py # 单视频处理流程 │ ├── merge.py # 图片拼接、字幕区域检测、音频文字提取 │ ├── getsrt.py # OCR解析、字幕定位、去重、SRT生成(含并发OCR) │ ├── whisper_manager.py # Whisper 管理器(线程安全单例) │ ├── Ocr/tencentcloud_ocr.py # OCR API 封装(内部Youtu服务) │ ├── VideoProcessing/multithread_algo.py # FFmpeg 抽帧 │ └── log/log_manager.py # 统一日志管理器(每视频状态线程本地) └── video/ # 视频文件存放目录 ``` ## 处理流程 ``` 1. 从 COS 下载视频(可选) ↓ 2. FFmpeg 抽帧(每秒 3 帧,fps=3.0 精确) ↓ 3. OCR 检测字幕区域 & 水印过滤 ↓ 4. 字幕区域裁剪 & 多帧拼接为大图 ↓ 5. 对拼接图/单独帧并发调用 OCR ↓ 6. Whisper 提取首尾音频文字(辅助校验) ↓ 7. 字幕定位 & 文本质量评估 & 相似帧合并去重 ↓ 8. 生成 SRT 字幕文件 ↓ 9. 上传结果到 COS & 记录元数据/运行统计 ``` ## 环境要求 - Python 3.10+ - FFmpeg(`ffmpeg` + `ffprobe`,**抽帧和音频都依赖**,需加入 PATH) - coscli(COS 命令行工具,配置 `coscli_path`) - CUDA(可选,Whisper GPU 加速) ## 安装依赖 ```bash pip install -r requirements.txt ``` Linux 上若 `numpy`/`scikit-learn`/`av` 卡在源码编译(PyAV 编译需系统 ffmpeg 开发库),强制用预编译 wheel: ```bash pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple --only-binary=av,numpy,scikit-learn ``` 首次运行会从 HuggingFace 下载 Whisper 模型;国内建议先设镜像: ```bash export HF_ENDPOINT=https://hf-mirror.com ``` ## 配置说明 编辑 `config/config.json`: ```json { "tencentcloud": { "ocr": { "secret_id": "...", "secret_key": "...", "endpoints": ["http://IP1:PORT", "http://IP2:PORT"] }, "cos": { "secret_id": "...", "secret_key": "...", "region": "ap-chongqing", "bucket": "..." } }, "audio": { "model_size": "small" }, "splitframe": { "interval_seconds": 0.33, "download": true, "upload_path": "cos://your-bucket/path", "delete_video": false, "coscli_path": "./coscli-linux-amd64", "cosconfig_path": ".cos.yaml" }, "subtitle": { "min_confidence": 50, "similarity_threshold": 0.7, "ocr_workers": 10 } } ``` ### 配置项说明 | 配置项 | 说明 | |--------|------| | `tencentcloud.ocr.{secret_id,secret_key}` | OCR 服务凭证 | | `tencentcloud.ocr.endpoints` | OCR 服务 IP 列表(多个时按 QPS 加权分发,失败自动摘除重试);不填回退到内置单端点 | | `tencentcloud.cos.{secret_id,secret_key,region,bucket}` | COS 凭证与桶信息 | | `audio.model_size` | Whisper 模型:`tiny`/`base`/`small`/`medium`/`large-v3`,默认 `small` | | `splitframe.interval_seconds` | 抽帧间隔,`0.33` 表示每秒 3 帧 | | `splitframe.download` | 是否从 COS 下载视频 | | `splitframe.delete_video` | 处理完是否删除本地视频 | | `splitframe.coscli_path` / `cosconfig_path` | coscli 路径 / COS 配置文件 | | `subtitle.min_confidence` | OCR 最低置信度阈值 | | `subtitle.similarity_threshold` | 文本相似度阈值 | | `subtitle.ocr_workers` | getsrt 阶段 OCR 并发线程数(默认 10) | ## 使用方法 ### 批量处理 ```bash python main.py --source-list ./text2 --max-workers 10 ``` ### 命令行参数 | 参数 | 默认值 | 说明 | |------|--------|------| | `--source-list` | `./text2` | 任务 txt 文件所在目录 | | `--max-workers` | 自动(按本机CPU核数) | 最大并发数;不填/传0则自动选(若本机IP在 `tencentcloud.ocr.endpoints` 里,判定为OCR共置机,自动打对折让资源;再按可用磁盘÷每视频预估占用(`dispatch.est_disk_gb_per_video`,默认2G)收紧一次,两者取小;最后还有个硬上限30,超高核数机器也不会自动选出离谱的并发数) | | `--mem-guard-gb` | `2.0` | 可用内存低于此值(GB)时暂停启动新视频,防 OOM;设 `0` 关闭 | | `--disk-guard-gb` | `10.0` | 本地磁盘可用空间低于此值(GB)时暂停启动新视频,给下载/抽帧/合成图预留空间,防止磁盘写满导致级联失败;设 `0` 关闭 | 启动时会打印一行机器资源(CPU 核数 / 可用内存 / 可用磁盘 / 负载)与当前并发设置,并对不合理的参数(内存/磁盘阈值过高、并发数过大/过小)给出告警,便于跑前判断。内存保护仅在 Linux 生效(读 `/proc/meminfo` 的 `MemAvailable`);磁盘保护跨平台(`shutil.disk_usage`)。机器无 swap 时内存保护尤其重要——可用内存触底会被暂停而非被 OOM 杀进程。 ### 任务列表格式 在 `--source-list` 目录下创建 `.txt` 文件,**每行一个完整的 COS 路径**(上传目标目录由该路径自动推导,无需 `--cos-target`): ``` cos://bucket/0004/data/XXX/XXX_p1/XXX_p1.mp4 cos://bucket/0004/data/XXX/XXX_p2/XXX_p2.mp4 ``` 每个 txt 处理完会被删除;主循环持续监控目录直到没有 txt。**跨运行续传/去重**通过读取 `数据.jsonl` 的 `video_cos_path` 实现(不依赖 `./success/`)。 ### 压测 OCR 端点 / 多 IP 负载均衡 OCR 服务有多个 IP 时,先压测每个 IP 的实际 QPS,运行时按 QPS 加权把请求分发到不同 IP: ```bash # 1) 在 config.json 的 tencentcloud.ocr.endpoints 填上所有 IP # 2) 压测各端点 QPS,结果写入 config/ocr_weights.json python bench_ocr_endpoints.py [样例图片] --requests 60 --concurrency 10 # 3) 之后正常跑 main.py,OCR 请求会按权重自动分发;某端点连续失败会被冷却摘除并换端点重试 ``` 不跑压测时,所有端点等权轮询;压测产出的 `config/ocr_weights.json` 存在则按 QPS 加权(错误率>50% 的端点权重置 0,不参与分发)。 ### 调试 SRT 逻辑 ```bash python tools/rerun_srt.py ./split//composite ``` 复用已有 `ocr_result.jsonl` 重生成 SRT,不重新调用 OCR,用于快速迭代 `getsrt.py` 的去重/合并/时间轴逻辑。注意它**不重新抽帧**,无法验证抽帧相关改动。composite 目录现在处理完就随 `split_dir` 一起删了(不再上传/保留到 `./composite/`),所以这条命令只在处理还没走完清理那一步之前有效——比如直接 `import tool.process` 调用 `process_single_video()` 单独调试时(这条路径不经过 `main.py`/`run_worker.py` 的清理逻辑)。 ## 输出说明 `