ARTICLE DETAIL

资讯详情

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

ICPR MTWI 2018网络图像文本检测与识别实战拆解

ICPR MTWI 2018网络图像文本检测与识别实战拆解 简介面向计算机、数学、电子信息等专业学生与竞赛选手该压缩包提供了一套完整的端到端场景文字识别竞赛方案。项目核心采用CNNRNNCTC架构覆盖数据预处理、字符集生成、TFRecord制作、模型定义、训练与推理全流程代码结构清晰下载后可直接运行也方便结合自身数据进行二次开发与算法复现。压缩包共24个文件大小约2.31MB包含4个Python脚本和2个Jupyter Notebook前者实现模型与数据读取后者分步演示了预处理流程另有XML配置、JSON设置、Markdown说明等辅助文件并附带了原版论文PDF与竞赛PPT便于深入理解技术细节。目前已有86人学习浏览。该项目无论是用于课程设计、毕业设计还是作为OCR方向入门实践都能帮助读者快速建立完整的项目工程认知掌握从数据准备到模型训练验证的排错思路。1. ICPR MTWI 2018 挑战赛网络图像文本检测与识别拆解为何值得复盘ICPR MTWI 2018 挑战赛的参赛代码包表面是“源码 项目说明 PPT”核心其实是一个工程决策集合网络图像上的多类型文本怎么检测、怎么识别、怎么在 F1 口径下对上评估脚本。MTWI 的 M 指 multi-type数据从网页与社交平台里的真实图片中来文字形态涵盖横排、竖排、弧排、压图、混排很多图里文字与背景花纹的灰度几乎相同。这和 ICDAR 2015 以自然拍摄为主、背景相对规整的场景文本语料差别很大所以“按网络图的排版特性裁剪检测与识别”才是这个项目真正沉淀的经验。下面按标注格式与评测口径、检测器选型、识别器调参、提交物组织四条线展开写的是这类挑战赛里被反复验证过的常规做法可以直接当成复现和改参的对照表。2. MTWI 2018 的数据格式与评测口径先读“怎么算对”再选检测器文本检测任务的数据包一般按照 images / labels 两级组织labels 里每个同名 JSON 对应一张图。先读这段标注再写模型能少踩不少格式坑{ file_name: img_0042.jpg, boxes: [ [[312, 208], [451, 208], [451, 248], [312, 248]], [[180, 348], [202, 312], [253, 327], [231, 363]] ], content: [全场五折, 限时抢购], ignore: [0, 0], _note: 仅演示结构真实数据不含注释字段 }boxes的每个元素按左上、右上、右下、左下的顺序存一个四边形的四角坐标content是对应的文本串ignore为 1 表示该框不参与评分常用于模糊、截断或跨图的文本。读取后的第一步不是训练而是可视化对齐随机抽 100 张图把标注框画回原图检查坐标系、宽高顺序和 ignore 遮挡关系。坐标顺序出错时评测脚本不会报警IoU 会直接变成 0这种坑只有在可视化阶段才容易暴露。from shapely.geometry import Polygon def quad_iou(pred_pts, gt_pts): # pred_pts / gt_pts: [[x1,y1], [x2,y2], [x3,y3], [x4,y4]] pred_poly Polygon(pred_pts) gt_poly Polygon(gt_pts) # buffer(0) 修复存在自相交的四边多边形否则 intersection 可能抛异常 if not pred_poly.is_valid: pred_poly pred_poly.buffer(0) if not gt_poly.is_valid: gt_poly gt_poly.buffer(0) inter pred_poly.intersection(gt_poly).area union pred_poly.area gt_poly.area - inter return inter / union if union 0 else 0.0buffer(0)是 Shapely 里修复自相交多边形的标准做法用于处理预测坐标中出现两个点几乎重合的情况。除以 0 的边界对应空文本框或多边形面积退化竞赛评测通常不会给这种框计分因此在评估脚本里返回 0.0 而不是中断。2.1 检测 F1 判定的三个调节旋钮IoU 阈值、置信度、NMS 重叠检测任务的最终指标通常是 F1。Precision 和 Recall 的配对逻辑是一个预测框与某个真值框的 IoU 大于等于 0.5并且这个真值框没有被 IoU 更高的预测框占用才算命中。同一个真值同时命中多个预测时只保留最高分其余作为 FP 处理。调节最终分数的有三个旋钮参见下表。调节方向对 Precision 的影响对 Recall 的影响排查建议提高置信度阈值上升下降漏检过多时先调到 0.5 看召回能否拉回提高 NMS 重叠阈值通常上升下降重复框来自同一文本时应调低 NMS 阈值合并提高 IoU 判定阈值下降下降检测框不够精确时逆向调损失权重而不是调阈值这三个参数中置信度与 NMS 在训练脚本就能控制IoU 判定阈值由评测脚本决定不能改。实际项目里最常出问题是把 NMS 阈值设成跟通用目标检测一样的 0.5文本框之间密集排布时一堆框没有被合并召回反而掉下去。2.2 本地评估脚本要复刻逐图 F1而不是全表累计竞赛的指标一般按图片逐一计算 F1 再取平均跟把全部检测框聚在一起算全局 F1 的结果往往不一样。一张图里有 10 个文本框另一张只有 1 个逐图均值会把“只有 1 个框的那张图”的权重放大。复现评估的命令通常长这样# 指定逐图计算模式确保与官方评分口径一致 python eval.py \ --gt_dir ./labels \ --res_dir ./result \ --iou_thresh 0.5 \ --mode per_image--mode per_image表示逐图计算再平均--iou_thresh是判定阈值。跑通这条命令后把本地分值与官方排行榜给出的分数作对比差值稳定在正负 0.2 以内评估链路才算可信。如果两边差值过大优先怀疑坐标归一化方式原图尺寸缩放后没有回放和框格式翻转而不是模型本身。2.3 标注边界情况ignore 区域、无文本图与多框重叠数据里比误标更麻烦的是三类边界情况。第一类ignore 区域如果被当成正样本喂进训练模型会刻意学习框出高纹理的背景块第二类整张图没有文本评测中输出空列表不会加分也不会扣分但输出任意框都会按 FP 拉低 precision第三类多个文本框互相重叠比如海报标题和装饰线条叠在一起像素级损失会来回震荡。读取数据时专门生成一个 ignore mask把 ignore 区域排除在 loss 计算之外可以在数据阶段就消掉很大一块噪声。3. 文本检测基线CTPN 的适用边界与 EAST 四边形回归参数CTPN 是将文本检测分解成一组垂直锚框预测的较早方案。它在 VGG16 的 conv5 特征图上以宽度约 16 像素的滑窗为单位预测每个窗口内文本存在的置信度和垂直偏移再用双向 LSTM 把同一行上的相邻窗口连接成线。对水平拍摄、方向稳定的数据CTPN 的管线清晰、后处理容易理解但在网页来源图像里文字排布经常带旋转竖排标题和弧排装饰文字让它的垂直锚框直接失效。遇到竖排文字就要旋转整张图再跑一遍推理时间翻倍F1 却不见得回来。公开对比里常见的结果是 CTPN 在横向文本的 recall 上接近 0.8旋转文本超过 15 度之后明显下降。下面三个检测器在一组综合数据上的常见手感如下。检测器水平文本倾斜与竖排训练成本后处理复杂度CTPN好差需要旋转输入中低EAST好中低中PSENet好好偏高高MTWI 数据集里的网络图片以中文海报、产品图和横幅为主旋转角分布跨度大使用过程中 EAST 往往是最先被定为基线的方案。EAST 直接回归文本分割掩码和文本框的四点坐标省掉了区域提议的环节训练和推理都简单。3.1 EAST 的三项配置输入尺度、分类损失与回归损失EAST 的输出包含两部分score map 预测每个像素属于文本区域的概率geometry map 输出该像素所属文本框的偏移量。训练脚本的常见入口参数如下# 短边 720 是速度和精度的中间取值只有一张 11GB 卡时换 512 和 batch 8 python train.py \ --dataset_dir ./data/MTWI \ --input_size 720 \ --batch_size 16 \ --lr 1e-3 \ --weight_decay 1e-4 \ --max_steps 100000 \ --checkpoint_path ./model/ckpt--input_size控制训练图的短边长度。720 是收敛速度与检测精度的中间地带显存充足时换成 1024 可以提升小字检测代价是训练速度下降约一半。--batch_size在 11GB 显存下用 8 比 16 稳妥16 的设置需要约 24GB 显存。分类分支一般用 dice loss处理文本像素与背景像素数量悬殊的问题比交叉熵稳定回归分支用 IoU loss让输出的四边形更贴近真值。总体 loss 为两者加权求和回归分支权重在 1.0 附近比较常见。3.2 后处理的决定性细节像素级候选框的合并策略EAST 输出的是像素级预测后处理要先把 score map 做阈值二值化再通过连通域分析和 NMS 合并出最终检测框。这里有两个参数影响结果阈值二值化设在 0.7 到 0.9 之间NMS 的重叠阈值在文本检测里通常比通用目标检测更严设为 0.2 到 0.3。文本行在像素层面的重叠比物体检测更频繁相同的前景区域会同时触发多个相邻像素的预测NMS 阈值设成 0.5 会留出一堆重复边界。如果样本里文本框重叠区域密集可以跳过全局排序剪枝直接使用 Locality-Aware NMS它的思想是把空间相邻的候选框合并在一起在重叠区域多时不牺牲精度。3.3 训练曲线正常但验证 F1 不动的排错思路检测模块最常见的卡点是 loss 下降、F1 不升。这种现象通常是正样本定义与后处理阈值脱节。score map 在训练时对所有真值框内部的像素都计为正样本如果 eval 阶段的阈值太高模型学到的“弱文本像素”被打掉召回始终上不去反之阈值太低背景纹理全部冒出来precision 被大量误检拖垮。建议把训练和评估的阈值统一并在训练过程中每 1000 步做一次快速验证把 score map 的分位值打印出来。如果观察到 score map 的分布整体低于 0.3说明回归分支主导了训练此时需要降低回归权重或者提高分类 loss 的占比来修正。4. 文本识别模块CRNN 参数边界与注意力解码替换检测器把文本区域裁剪出来后识别分支通常先用 CRNN 打底。CRNN 的构成是“卷积提取序列特征 双向 LSTM 建模上下文 CTC 做序列对齐”。它不需要把文本框逐字切分图像和文本标签直接配对就能训练这在样本标注成本上优势巨大。网络图中的中文文字识别与英文最大的区别是字符集规模中文字符可以从几千扩展至一两万输出维度变大之后尾部类别的拟合质量直接影响整体分数。4.1 字集长度、高度归一化与双向层宽度的联动数据预处理阶段通常把裁剪图像缩放到固定高度 32宽度按比例缩放。BiLSTM 的隐藏层宽度在 256 附近是一个常见起点文本长度超过 20 个字符时用到 512 往往收益更明显。字集的构建比模型参数更容易被忽略直接从训练标注里统计字符会把出现次数极少的生僻字也纳入输出空间这些类别由于样本不足在验证时贡献了不成比例的误差。常规做法是先用高频几百字训练一个稳定模型跑通整个评估流程再用完整字集训练最终版本。下表给出一组常见基线参数。参数基线值调整方向优先级输入高度3248当裁剪框里有多行小字中BiLSTM hidden256512当平均文本长度大于 20中学习率1e-33e-4中文字集更大时高字符集大小高频 500 起全量 8000高学习率的调整和字符集规模强相关。几千个输出类时1e-3 的初始学习率会让权重更新跨度过大训练损失曲线出现周期性震荡降到 3e-4 后曲线平滑很多。4.2 CTC 解码的三个典型误识重复字、数字与单位粘连、空白字符CTC 在长文本上的一个典型问题是重复字符合并。例如把“欢迎光临”识别成“欢欢迎迎光临”原因是 CTC 的输出在时序上把同一区域预测了多次解码时没有正确合并。反向的另一个问题是数字与单位被拆开“13 号楼”的中间空格由背景产生如果字符集里没有空格类解码会直接丢失这个字符。下面是最小可用的 CTC 解码逻辑不依赖额外库适合在调试时直接嵌入推理脚本def decode_ctc(probs, alphabet, blank_id0): # probs: (T, num_classes)T 是时间步数num_classes 是字符类总数 result [] prev blank_id for t in range(probs.shape[0]): cls int(probs[t].argmax()) # 空白类跳过与上一个非空白类相同的字符合并 if cls ! blank_id and cls ! prev: result.append(alphabet[cls - 1]) prev cls return .join(result)合并的逻辑是“连续相同”才合并。如果两个相同字符之间隔了一个空白类则它们会被保留为两个字符这个细节处理错会直接影响识别“11”这类连续数字的准确率。实际工程里更推荐直接使用 PyTorch 的 CTC 解码接口上面的裸实现只用于理解逻辑不过它在验证推理时比库函数更容易单步跟踪。4.3 用注意力解码替换 CRNN 时重点盯两个退化现象中长文本上 CRNN 的序列建模有限换成 attention 解码的 encoder-decoder 结构后精度通常更高。attention 训练时最值得盯的是两个现象。第一个是解码长度超长时 attention 权重扩散模型在多个时间步里反复看向同一段特征输出重复字符第二个是注意力权重集中在一个很小的空间范围不移动这种情况通常是裁剪框内存在明显的噪声纹理把 attention 钉死在那个位置。处理方式有两种对训练样本做随机缩放和随机裁剪增强让模型看到不同位置起始的文本或者在解码阶段加上长度惩罚当输出长度明显超过输入宽度对应的字符数时终止解码。验证时可以把每步 attention 的峰值位置打印出来确认权重是否从左往右平滑移动这一步对排错比看 loss 曲线更直观。5. 提交前的收尾验证脚本、项目说明结构与 PPT 主链路参赛源码的组织方式决定了它之后还能不能继续改。目录结构上最常见的问题是代码全堆在一个入口文件里检测与识别逻辑通过命令行参数切换到后期改一处参数会波及其他分支。5.1 项目结构以三个入口收口train.py、infer.py、评估脚本ocr_competition/ ├── configs/ # 训练与推理配置 ├── data_loader/ # 数据集读取与坐标变换 ├── models/ # 检测器与识别器 ├── tools/train.py # 训练入口 ├── tools/infer.py # 测试图 → 提交文件 ├── eval/ # 评测脚本封装 ├── requirements.txt └── README.md这样组织之后复查的人顺着三个入口就能理清项目train.py 负责训练参数infer.py 负责提交格式eval 负责分数对齐。检测与识别是两个独立目录避免调用链互相牵连。5.2 项目说明文档写清三个状态而不是一段叙述项目说明容易写成“任务理解 思路描述”缺了可复现的关键参数。实际有效的写法是记录三个状态训练框架与 GPU 型号本地验证的 F1 分数与提交分数的差异数据增强的开关清单。这三项不需要长篇展开每项两到三行读者就能判断这个项目在他自己的环境里能不能跑通。验证集划分也要写清楚是按图片名随机切还是按网页域名切两种切法对指标的影响差异很大。5.3 PPT 按一条主线讲参数只保留影响得分的五个左右PPT 的结构建议是一页展示检测的失败样例这是全篇最强的记忆点三到四页讲检测到识别的完整链路每页只保留一个对比维度例如带旋转与不带旋转的召回差异最后一页落到跨模块实验比如“检测框宽度对识别精度的影响”。超参不需要全部铺在页面上挑选影响最终分数最大的五个参数——输入尺度、置信度阈值、NMS 阈值、学习率、字集规模——放在说明页。每个数值都对应一句“改了什么、分数变了多少”评审或者后来的维护者能快速评估这个项目的有效性比罗列一屏参数列表有用得多。本文还有配套的精品资源点击获取
返回列表