{
  "title": "实践：文字与马赛克自动擦除 + 画质增强——一条 CPU 上的完整图像处理流水线",
  "url": "/posts/practice-erase-text-mosaic/",
  "permalink": "https://hackcv.com/posts/practice-erase-text-mosaic/",
  "date": "2026-08-23",
  "lastmod": "2026-08-23",
  "author": "hackcv",
  "description": "PP-OCRv4 DBNet 文字检测 + 纯 CV 马赛克检测 + 多来源掩码 OR 合并 + LaMa 擦除，再接「分析→修复→放大→精修」画质增强四阶段，全程 CPU；含色彩保真踩坑实录。",
  "categories": ["研究简报"],
  "tags": ["AI","OCR","图像擦除","PP-OCRv4","马赛克检测","实践"],
  "cover": "https://picsum.photos/seed/%E5%AE%9E%E8%B7%B5%E6%96%87%E5%AD%97%E4%B8%8E%E9%A9%AC%E8%B5%9B%E5%85%8B%E8%87%AA%E5%8A%A8%E6%93%A6%E9%99%A4-\u0026#43;-%E7%94%BB%E8%B4%A8%E5%A2%9E%E5%BC%BA%E4%B8%80%E6%9D%A1-cpu-%E4%B8%8A%E7%9A%84%E5%AE%8C%E6%95%B4%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E6%B5%81%E6%B0%B4%E7%BA%BF/1200/675",
  "readingTime": 1,
  "wordCount": 296,
  "content": "\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e一句话结论\u003c/strong\u003e：一套纯 CPU 的端到端图像处理流水线——\u003cstrong\u003ePP-OCRv4 DBNet 定位文字（0.2~0.5s）+ 纯 CV 检测马赛克（实时）+ 掩码 OR 合并交给 LaMa 擦除（2.1s）\u003c/strong\u003e，之后可选接「分析→修复→放大→精修」四阶段画质增强。实测字幕条场景全流程 ≈3s/帧（1920×1080）。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"背景与动机\"\u003e背景与动机\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e场景\u003c/strong\u003e：批量去字幕/水印/标注、隐私打码去除、老照片抢救\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e痛点\u003c/strong\u003e：全量 OCR（含识别分支）又大又慢；马赛克检测常被做成要训练的模型；擦除后画质往往需要增强——\u003cstrong\u003e没有一个纯 CPU 可跑的完整闭环\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e约束\u003c/strong\u003e：与擦除基准篇相同——ONNX Runtime CPU 路线\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"核心思路三层流水线\"\u003e核心思路（三层流水线）\u003c/h2\u003e\n\u003ch3 id=\"第一层检测自动生成掩码\"\u003e第一层：检测（自动生成掩码）\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e文字检测（PP-OCRv4 DBNet）\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e只用\u003cstrong\u003e检测分支\u003c/strong\u003e（DB 文本检测），不跑识别——模型 \u003cdel\u003e4.5 MB、CPU 0.2\u003c/del\u003e0.5s/张\u003c/li\u003e\n\u003cli\u003e输出文字多边形框 → 转二值掩码 → 按框膨胀覆盖笔画边缘\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e马赛克检测（纯 CV，零模型）\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e基于马赛克的视觉特征：\u003cstrong\u003e块状网格 + 局部高频缺失\u003c/strong\u003e——用网格梯度一致性判定\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e--mosaic-grid-thr\u003c/code\u003e 控制严格度（0.7~0.9 是多数图的安全区间，人脸打码建议 0.9）\u003c/li\u003e\n\u003cli\u003eCPU 实时（毫秒级），无需加载任何模型\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"第二层掩码合并--擦除\"\u003e第二层：掩码合并 + 擦除\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e多来源掩码（文字 + 马赛克 + 手动涂抹）\u003cstrong\u003e按位 OR\u003c/strong\u003e 合并为一张总掩码\u003c/li\u003e\n\u003cli\u003e统一 \u003ccode\u003e--dilate + --feather\u003c/code\u003e 后交给 LaMa（三模型选型见基准篇）\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e--roi x,y,w,h\u003c/code\u003e 限定检测区域——只擦字幕条，避免误伤画面主体\u003c/li\u003e\n\u003cli\u003e多个文字框先经 \u003ccode\u003e_merge_boxes\u003c/code\u003e（IOU 合并）减少碎片掩码；再统一膨胀\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e检测参数（真实实现值）\u003c/strong\u003e：DBNet 推理阈值 \u003ccode\u003ethresh=0.2\u003c/code\u003e、框过滤 \u003ccode\u003ebox_thresh=0.35\u003c/code\u003e、\u003ccode\u003eunclip_ratio=1.8\u003c/code\u003e（文字框外扩比例）——\u003ccode\u003eunclip_ratio 1.8\u003c/code\u003e 意味着文字框在生成掩码时向外扩 1.8 倍，正好补足笔画边缘残留，是\u0026quot;文字擦干净\u0026quot;的关键参数。\u003c/p\u003e\n\u003ch3 id=\"第三层可选画质增强四阶段\"\u003e第三层（可选）：画质增强四阶段\u003c/h3\u003e\n\u003cp\u003e擦除后接 \u003ccode\u003eenhance.py\u003c/code\u003e 的**「分析 → 修复 → 放大 → 精修」**流水线（全部 ONNX Runtime CPU）：\u003c/p\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003e阶段\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e做什么\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e关键模型（CPU 验证）\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e分析\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eNIMA 画质评分 + 实拍/二次元判别\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eNIMA mobilenet（~MB级）\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e修复\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e去 JPEG 伪影 / 去噪 / 去运动模糊\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e1xDeJPG/1xDeNoise（PLKSR）、1x-hurrdeblur（0.18 MB，极快）\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e放大\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e超分 2x/4x\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eSPAN-4x（1.7 MB 最快）、Real-ESRGAN general-fast（5 MB 细节扎实）、Real-CUGAN（二次元）\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e精修\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e人脸修复\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eYOLOv8n-face 检测 5 关键点 → GPEN-BFR-512（284 MB）\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e预设：\u003ccode\u003efast\u003c/code\u003e（仅锐化）/ \u003ccode\u003ebalanced\u003c/code\u003e（默认 2x SPAN）/ \u003ccode\u003equality\u003c/code\u003e（4x Real-ESRGAN + 全修复 + 人脸）/ \u003ccode\u003eanime\u003c/code\u003e。\u003c/p\u003e\n\u003ch2 id=\"关键踩坑色彩保真放大不该改变颜色\"\u003e关键踩坑：色彩保真（放大不该改变颜色）\u003c/h2\u003e\n\u003cp\u003e早期 \u003ccode\u003equality\u003c/code\u003e（4x + 人脸）后\u003cstrong\u003e整体偏色发暗\u003c/strong\u003e，根因两处：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e白平衡误触发\u003c/strong\u003e：旧判据用\u0026quot;全图三通道均值极差\u0026quot;估色偏（阈值 12），把夕阳/绿植/红砖这类\u003cstrong\u003e本来就有主色调\u003c/strong\u003e的照片误判成偏色而去自动白平衡。修复：只在**本该中性（低饱和）**的像素上估光源色偏，阈值提到 22——正常照片读数普遍 \u0026lt;10，够不到阈值，默认不动色彩；白平衡加护栏（增益限幅 1.30 + 保亮度），真偏色仍能修（钨丝灯 60→12）。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e超分模型自带通道偏置\u003c/strong\u003e：实测 \u003ccode\u003eSPAN-4x.onnx\u003c/code\u003e 输出 \u003ccode\u003e≈0.958·in + bias\u003c/code\u003e（bias≈R−0.8/G+3.3/B+6.1），整体压暗约 4% 且红降蓝升——\u0026ldquo;一放大颜色就变了\u0026quot;的根因。修法：\u003cstrong\u003e低频对齐\u003c/strong\u003e（\u003ccode\u003eenhance.align_low_freq\u003c/code\u003e）——超分只该补高频，整体明暗/色彩应等于输入，把输出低频拉回输入低频即可；对本身干净的 Real-ESRGAN（偏置 \u0026lt;1）近似无操作，不是给 SPAN 写死的魔法数。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e修复后 \u003ccode\u003equality\u003c/code\u003e/\u003ccode\u003ebalanced\u003c/code\u003e 通道增益回到 ~1.000（最大偏离 \u0026lt;0.005）。\u003ccode\u003e--keep-color\u003c/code\u003e 可彻底交给用户手控。\u003c/p\u003e\n\u003ch2 id=\"实测数据\"\u003e实测数据\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 检测 + 擦除\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epython erase.py -i frame.jpg -o out.png --detect-text                      \u003cspan style=\"color:#75715e\"\u003e# 整图文字（去水印）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epython erase.py -i frame.jpg -o out.png --detect-text --roi 50,450,1020,180 \u003cspan style=\"color:#75715e\"\u003e# 只擦字幕条\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epython erase.py -i frame.jpg -o out.png --detect-mosaic --mosaic-grid-thr 0.9\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epython erase.py -i frame.jpg -o out.png --detect-text --detect-mosaic      \u003cspan style=\"color:#75715e\"\u003e# 掩码 OR 合并\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 擦除 + 增强 组合\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epython erase.py -i text.jpg -o erased.png --detect-text --enhance --enhance-preset balanced\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epython enhance.py -i old.jpg -o out.png --preset quality --keep-color      \u003cspan style=\"color:#75715e\"\u003e# 老照片抢救保色\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003e步骤\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e耗时（CPU）\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eDBNet 文字检测\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e0.2 ~ 0.5 s/帧\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e马赛克检测（纯 CV）\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e实时（毫秒级）\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eLaMa 擦除\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e~2.1 s/帧\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003e字幕条全流程\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003e≈3 s/帧（1920×1080）\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e增强 balanced（2x）\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e秒级；quality（4x+人脸）数十秒\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"适用边界与取舍\"\u003e适用边界与取舍\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e适合\u003c/strong\u003e：去字幕/水印/标注、隐私打码、视频帧批量清理、擦除后画质增强的完整闭环\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e不适合\u003c/strong\u003e：曲形艺术字（掩码复杂擦除易糊）、\u0026lt;12px 小字（DBNet 易漏）、对色彩绝对敏感的出版级场景（需人工校色）\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e取舍\u003c/strong\u003e：只用 DBNet 检测分支换速度；需要\u0026quot;识别文字内容\u0026rdquo;（如敏感词判定）再接识别分支，但延迟显著增加——按需取舍\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"复现要点\"\u003e复现要点\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e检测模型：PP-OCRv4 DBNet ONNX（~4.5 MB），增强模型约 1 GB 由 \u003ccode\u003escripts/fetch_enhance_models.py\u003c/code\u003e 从 \u003cstrong\u003ehf-mirror.com\u003c/strong\u003e 拉取\u003c/li\u003e\n\u003cli\u003e验证脚本：\u003ccode\u003escripts/test_color_fidelity.py\u003c/code\u003e（秒级，覆盖误触发/真偏色/护栏/keep-color 四类）\u003c/li\u003e\n\u003cli\u003e环境：Python 3.13 + OpenCV 5.0 + onnxruntime，纯 CPU\u003c/li\u003e\n\u003c/ul\u003e\n",
  "summary": " 一句话结论：一套纯 CPU 的端到端图像处理流水线——PP-OCRv4 DBNet 定位文字（0.2~0.5s）+ 纯 CV 检测马赛克（实时）+ 掩码 OR 合并交给 LaMa 擦除（2.1s），之后可选接「分析→修复→放大→精修」四阶段画质增强。实测字幕条场景全流程 ≈3s/帧（1920×1080）。\n背景与动机 场景：批量去字幕/水印/标注、隐私打码去除、老照片抢救 痛点：全量 OCR（含识别分支）又大又慢；马赛克检测常被做成要训练的模型；擦除后画质往往需要增强——没有一个纯 CPU 可跑的完整闭环 约束：与擦除基准篇相同——ONNX Runtime CPU 路线 核心思路（三层流水线） 第一层：检测（自动生成掩码） 文字检测（PP-OCRv4 DBNet）：\n只用检测分支（DB 文本检测），不跑识别——模型 4.5 MB、CPU 0.20.5s/张 输出文字多边形框 → 转二值掩码 → 按框膨胀覆盖笔画边缘 马赛克检测（纯 CV，零模型）：\n基于马赛克的视觉特征：块状网格 + 局部高频缺失——用网格梯度一致性判定 --mosaic-grid-thr 控制严格度（0.7~0.9 是多数图的安全区间，人脸打码建议 0.9） CPU 实时（毫秒级），无需加载任何模型 第二层：掩码合并 + 擦除 多来源掩码（文字 + 马赛克 + 手动涂抹）按位 OR 合并为一张总掩码 统一 --dilate + --feather 后交给 LaMa（三模型选型见基准篇） --roi x,y,w,h 限定检测区域——只擦字幕条，避免误伤画面主体 多个文字框先经 _merge_boxes（IOU 合并）减少碎片掩码；再统一膨胀 检测参数（真实实现值）：DBNet 推理阈值 thresh=0.2、框过滤 box_thresh=0.35、unclip_ratio=1.8（文字框外扩比例）——unclip_ratio 1.8 意味着文字框在生成掩码时向外扩 1.8 倍，正好补足笔画边缘残留，是\u0026quot;文字擦干净\u0026quot;的关键参数。\n"
}
