夜幕降临,你走进一条夜市街。头顶的招牌五花八门:横的、竖的、绕着灯筒弯成弧的;有的亮得刺眼,有的被烟火熏得模糊。人类扫一眼就能说出“这里有字、那里也有字”,但电脑看到的只是一堆灰蒙蒙的像素格子。所谓文字检测,就是教会电脑在图片中回答两个问题:图里有没有文字?文字框在哪个位置?本文请来两位性格迥异的“招牌巡检员”:一位叫小切,擅长“切片检查法”(对应 CTPN 算法),把画面切成竖条逐条判断再拼接;一位叫小温,擅长“温度图法”(对应 DB 算法),给每个位置打“文字概率分”,再用一条能学习的红色等温线把文字圈出来。读完本文,你会明白他们各自的绝活、软肋,以及什么时候该请谁出马。
文字检测是 OCR 的第一道工序,也是决定识别上限的咽喉;掌握 CTPN 与 DB 的原理与取舍,能让你在真实项目中快速选型、少走弯路——这是每位 AI 工程师都值得拥有的看家本领。
目录
可视化演示
对比展示CTPN水平文字检测与DB可微二值化两种算法的检测流程,包括候选框生成、概率图计算与自适应阈值二值化过程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
CTPN文字检测 通过固定宽度锚框生成文字候选序列,RNN连接上下文信息 候选框合并为完整文字行,适用于水平排列文本 B_text=merge({b_i|score(b_i)>τ}) CTPN擅长检测水平排列的长文本行
检测任务概述:给照片做“找字体检”
夜市入口人声鼎沸,一排排招牌横的竖的、亮的暗的。如果让一个从没见过汉字的实习生来找招牌,他会先问:“我要找的东西长什么样?”文字检测给计算机的答案也一样:圈出“哪里有文字”,至于写的是什么,那是后面识别模型的事。这第一步定位,专业上叫文字检测(Text Detection),是整个 OCR 管线的第一道工序,决定了后面识别模型能不能在正确的地方“下手”。
文字检测和通用目标检测相似——都要用框把目标圈出来,但又更刁钻:文字可以是一两个字,也可以是长长一串;可以横排、竖排,还能绕着瓶子弯曲;光照不均、运动模糊、透视变形都是家常便饭。为了应对这些,业界演化出两大流派:一派走“回归框”路线,代表人物是 CTPN;另一派走“分割涂色”路线,代表人物是 DB。前者像直接伸手去抓目标,后者像先给整张图涂上颜色再圈范围。
不管哪一派,最后都要拿自己的预测框和真实框比一比谁贴得更紧。这个比对标准叫 IoU(Intersection over Union,交并比),它回答“你圈出来的框和真实文字框到底像不像”。
就像体检时量体温必须量准位置,体温计放歪了读数就失真。IoU 就是文字检测圈的“体温计”,两位高手的水平如何,先看它量出来的分数。这也是为什么所有 OCR 比赛的排行榜上,IoU 相关的指标永远排在第一位。
- 交集面积真实框 A 与预测框 B 重叠的那块区域,记作分子 |A∩B|。
- 并集面积两个框各自覆盖的面积总和再减去重叠部分,记作分母 |A∪B|。
- 比值结果交集除以并集得到一个 0 到 1 之间的分数,越接近 1 说明框得越准,检测任务通常要求 IoU 大于 0.5 才算命中。
CTPN核心原理:小切的“切片检查法”
小切是位经验老到的招牌巡检员,他的方法朴素得可爱:既然夜市招牌基本都横着挂,那我就把画面竖直切成一条条细片,像切吐司一样逐片检查——这片里有笔画的痕迹吗?有,就标记“是文字”,没有就跳过。全部检查完后,把相邻的“是文字”细片拼起来,完整招牌就出来了。
在计算机科学里,小切的“细片”叫垂直锚框(Vertical Anchor),宽度固定为 16 像素,高度可以从 11 像素到 400 多像素变化,以适应不同字号。这个设计背后有深刻的观察:文字天然具有序列属性,水平方向上下文连贯,即使切成细条,每条里依然保留着可判断的局部笔画信号,比如横折、竖钩的痕迹。
每个锚框会输出两类预测:一是“这片是不是文字”的置信度分数,二是垂直方向要不要上下微调的偏移量。因为锚框在水平方向排布得非常密集,相邻锚框的判断可以互相印证,之后再把“水平距离近”且“垂直方向重叠度高”的高分锚框连成一条文本线(Text Line)。这里有一个关键技术点:网络回归的不是绝对的像素坐标,而是归一化的垂直偏移。
小切不识字也能干活,他只看笔画纹理就能判断“这片像不像字的一部分”。但他有个致命前提:只信横着挂的招牌。遇到竖排的灯笼招牌,切片会断成一地碎渣,这正是他的软肋——也是小温后来居上的机会。
- 分子差值真实文字中心的垂直坐标 y\* 减去锚框中心的垂直坐标 y^a,得到位置偏差。
- 分母高度用锚框自身高度 h^a 做归一化,避免大号字和小号字在数值上没法比较。
- 回归结果v_j 是归一化后的垂直偏移,网络学的是这个相对量,训练更稳定、收敛更快。
CTPN网络结构:切片流水线车间
把小切的“切片法”工业化,就变成一条流水线:入口是照片,出口是“哪些细片是文字”。车间里三个工人各司其职,配合得天衣无缝。第一个工人是VGG16 骨干网络,负责把原始图像翻译成特征图——相当于把“亮度”翻译成“这里有没有笔画边缘”的语义信息。
第二个工人是BLSTM(双向长短期记忆网络),它是整个车间的灵魂。切片有个天然问题:某一小片可能恰好被反光或烟雾挡住,单看它根本判断不了是不是文字。BLSTM 在水平方向上来回“张望”:左边邻居说“我这边像字的中间”,右边邻居说“我这边像字的收尾”,那中间这片十有八九也是文字。这种序列上下文建模,让 CTPN 对遮挡和模糊天生更抗造。
第三个工人负责“打包发货”:在特征图的每个位置同时输出三类结果——文本/非文本分数、垂直坐标修正、水平边缘细化偏移。车间训练时会计算这三类任务的总损失:
车间出货后还有一道质检工序:先把置信度太低的切片丢掉,再做 NMS(非极大值抑制) 去掉彼此重叠的冗余框,最后把剩下的高分切片按邻近关系连成文本线。流水线让小切又快又准,但车间在规划时就没打算处理竖排——方向这个先验,从锚框设计那一刻起就写死了。
- 分类损失判断每个锚框是文字还是背景的交叉熵损失,监督“切片判断”是否准确。
- 垂直回归损失修正锚框上下位置的 smooth L1 损失,权重为 λ1,监督“高度微调”。
- 边缘回归损失修正文本线左右边界的回归损失,权重为 λ2,让拼接后的框左右更贴合。
DB可微二值化:小温的“温度等温线”
小温是气象员出身,他的名言是:“别一个一个框,先给整条街画温度。”他的思路和小切完全不同:不切条、不判断单个切片,而是把每个像素都打一个文字概率分(0 到 1 之间),形成一张概率图——文字区域像高温区一样发烫,背景像深秋的夜一样冰冷。
可热成像图有个毛病:边界是糊的。怎么把“热区”清晰地圈出来?传统做法是拿一个固定阈值(比如 0.5)去切:概率大于阈值就是文字,否则是背景。但不同招牌亮度不同、背景复杂程度各异,固定阈值在这条街刚调好,换个巷子就翻车。更致命的是,“切”这个操作是一个阶跃函数,导数处处为 0,梯度根本传不回去,模型没法通过训练学会“该怎么切”。
小温的高明之处在于:他把“切”这一步替换成了一个可微的 S 形近似。左边是传统二值化的阶跃判断,右边是 DB 提出的可微二值化(Differentiable Binarization):
从此,那条红色等温线不再是人工设定的常数,而是网络自己学出来的、每个位置都不同的“专属温度线”。它能绕过弯曲的灯箱、避开刺眼的反光,圈得又准又贴合。小温从此成了夜市招牌巡检界的传奇。
- 固定阈值判定左边是传统方式,概率值 P 大于等于固定阈值 t 就定为文字,输出硬性的 1 或 0。
- 可微差值右边用逐像素阈值 T_{i,j} 替换固定值 t,先算出“概率超出温度线多少”的差值。
- S 形压缩差值经过指数与 Logistic 函数后,被压到 0 到 1 之间,形成近似二值化的光滑曲线,k 控制曲线陡峭程度,全程可导。
DB网络架构:双屏幕气象站
小温的工位有两个大屏幕:一块显示“文字下雨概率”,另一块显示“雨线该画在哪里”。两块屏幕共享同一套雷达数据,却又各司其职。第一块屏幕输出的是概率图 P,回答“这个像素是不是文字”;第二块屏幕输出的是阈值图 T,回答“这里该设多高的温度线”。两者合成,就是最终的二值图。
雷达数据从哪来?网络骨干采用 ResNet 加 FPN(特征金字塔) 结构。浅层特征分辨率高、边缘清晰,能看清招牌的轮廓;深层特征语义强,能认出“这是文字不是灯带”。FPN 把各层的优点融合在一起:
推理阶段,小温的“双屏幕”可以精简:阈值图分支在部署时可以剥离,直接用概率图加固定阈值做二值化,速度还能再快一截。拿到二值图后,提取连通域,对每个连通域的轮廓做多边形近似(通常是 Douglas-Peucker 算法),再把多边形按收缩比例外扩还原,最终得到贴合任意形状的文本框。雷达越清晰,等温线越精准——这就是 DB 能拿下各种弯曲文字竞赛冠军的底气。
- 多尺度特征FPN 输出 P2 到 P5 四层特征,分辨率从细到粗,编码的信息从边缘细节到高层语义。
- 统一尺寸把 P3 到 P5 上采样到与 P2 相同的分辨率,才能逐位置对齐拼接。
- 融合卷积按通道拼在一起后过一个 3×3 卷积,得到既懂边缘又懂语义的融合特征 F。
训练与损失:给小温准备标准答案
光有方法论还不够,训练时得告诉小温“哪条等温线是对的”。如果直接把整个文字多边形当作正样本,模型学出来的边界会松松垮垮,经常“越界”框到旁边招牌上去。小温的训练法则有一条铁律:标准答案必须自带安全距离。
DB 的做法是用 Vatti 收缩算法把真实多边形向内收缩一圈,收缩后的多边形作为概率图的正样本区域,原多边形与收缩多边形之间的夹缝则当作难负样本。收缩距离不是随便拍的,它由多边形的面积和周长共同决定:
有了标签,还要配一套完整的损失函数来约束三个输出。概率图和二值图都用带难样本挖掘的二分类损失(聚焦在那些容易混淆的边界像素上),阈值图则用 L1 损失,只监督文字区域内部:
与小切的锚框回归不同,小温的训练标签是“面”而非“框”,收缩出的安全距离让等温线既不会内缩过头吃掉文字,也不会外溢到邻居招牌上。就像给气象员划定重点预报区域,小温画线时心里有了谱。
- 面积 A文本多边形的面积,面积越大,整体需要收缩的尺度也越大。
- 周长 L多边形周长越长,说明形状越细长,收缩距离要相应减小,防止细字消失。
- 收缩比例 rr 通常取 0.4,决定正样本区域缩到原来的多大,1−r² 是面积缩减系数。
- 收缩距离 dVatti 算法沿着每条边向内平移 d 个单位,生成收缩后的文本多边形标签。
评估与选型:两位高手同台竞技
夜市管理方要招一位总巡检员,两位高手拿着成绩单来应聘。成绩单上不能只写“我找到了 100 个招牌”,还得说清楚哪些是真招牌、哪些是误报。这就引出了文字检测的铁三角指标:精确率(Precision)、召回率(Recall) 和 F1 分数。
精确率回答“你报出来的招牌里,真有字的占多少”;召回率回答“街上所有招牌,你找到了多少”。只看精确率,小切可以只报最亮那一个招牌,精确率 100% 但漏掉一半;只看召回率,小温可以把所有灯箱都圈上,召回率 100% 但误报一堆。所以要用调和平均逼着两边都不偏科:
实际竞赛中还有一个隐性门槛:预测框与真实框的 IoU 必须大于 0.5 才算一次有效命中,这正是我们第一节讲的“体温计”在发威。综合对比两位高手:CTPN 在水平排版、结构化的文档场景下精度高、理论经典,但只能处理水平文字,后处理链路较长;DB 对任意形状通吃,推理极快(能用 RLE 加速做到实时),但对极小字和超长文本需要额外调参。选型口诀很简单:规整印刷体选小切,杂乱弯曲场景请小温。
- 精确率 P预测出的框里真正是文字的占比,太高说明“宁缺毋滥”,报得少但报得准。
- 召回率 R真实文字框里被找到的占比,太高说明“宁滥勿缺”,找得全但可能带噪声。
- 调和平均 F1当 P 和 R 都高时 F1 才高,任何一边偏科都会被严重拉低,倒逼模型均衡发展。
AI 应用场景
卡证票据的高精度 OCR 前置检测
阶段:数据预处理与检测定位
解决的问题:身份证、发票、快递单上的文字规整但常伴随拍照倾斜、反光。传统通用目标检测框定位不准,错误框直接喂给识别模型会放大误差,导致整张单据识别失败。
具体案例:某银行接入 OCR 识别身份证正反面信息。管线先用 CTPN 定位水平文本行,结合旋转校正把倾斜的身份证摆正,再送识别网络。上线后身份证号码识别准确率从 92% 提升到 99% 以上,验证了小切在规整场景的统治力。
电商商品图与街景招牌的任意形状文字检测
阶段:模型训练与推理
解决的问题:酒瓶弧形标签、奶茶杯身环绕字、街景中倾斜弯曲的灯箱,CTPN 这类水平检测器会漏检或把弯曲文字切成碎片。DB 的“温度图 + 可微二值化”能贴合任意形状。
具体案例:某电商平台对商品外包装图做合规审查,需要检测“仅限今日”“买一送一”等弯曲小字。改用 DB 后,对弧形瓶身文字的召回率从 61% 提升到 92%,且单图推理仅 12 毫秒,顺利接入实时审核流水线。
高分辨率文档版面高速分析
阶段:工程优化与部署
解决的问题:政务大厅每天扫描大量纸质表格,版面杂乱、字段繁多。逐像素分割类模型通常很慢,但 DB 推理阶段可剥离阈值分支、配合 RLE 编码加速,特别适合高分辨率文档的实时版面分析。
具体案例:某政务系统用 DB 实时框出扫描件的“姓名/日期/盖章区”,再裁剪交给下游识别,单页处理耗时从 200 毫秒降到 30 毫秒,省下的算力可以支撑更多并发请求。
Python 演示
import numpy as np def connect_textline(scores, gap_thresh=2): """CTPN 思想: 把连续的高分竖向切片连成一条文本线.""" lines = [] start = None for i, score in enumerate(scores): if score > 0.5 and start is None: start = i elif score <= 0.5 and start is not None: if i - start >= gap_thresh: lines.append((start, i - 1)) start = None if start is not None: lines.append((start, len(scores) - 1)) return lines def shrink_box(box, shrink_ratio): """把四边形按比例向中心收缩, 生成 DB 训练用的收缩标签.""" box = np.asarray(box, dtype=np.float64) center = box.mean(axis=0) return box + (center - box) * shrink_ratio def differentiable_binarization(prob_map, threshold_map, k=50): """DB 核心: 可微二值化, 替代不可导的固定阈值切割.""" return 1.0 / (1.0 + np.exp(-np.clip(k * (prob_map - threshold_map), -30, 30))) def db_inference(prob_map, threshold_map, min_area=4): """推理: 可微二值化后统计文字像素区域面积.""" binary_map = differentiable_binarization(prob_map, threshold_map) mask = binary_map > 0.5 return mask, int(mask.sum()) def main(): # 1. CTPN 切片连接: 模拟一条水平文本行的逐片置信度 scores = [0.9, 0.95, 0.98, 0.92, 0.1, 0.3, 0.88, 0.91, 0.86, 0.2] lines = connect_textline(scores) print("CTPN 连接的文本线切片索引:", lines) # 2. DB 标签收缩: 一个水平的矩形文本框 box = [(10, 10), (60, 10), (60, 40), (10, 40)] shrunk_box = shrink_box(box, 0.4) print("DB 收缩标签的第一个角点:", shrunk_box[0]) # 3. DB 推理: 模拟简单概率图与阈值图 prob_map = np.zeros((8, 8)) prob_map[2:6, 2:6] = 0.8 threshold_map = np.full((8, 8), 0.3) mask, area = db_inference(prob_map, threshold_map) print("DB 检测出的文字区域像素数:", area) print("二值化掩码形状:", mask.shape) if __name__ == "__main__": main()
def connect_textline(scores, gap_thresh=2)模拟 CTPN 后处理:把连续超过 0.5 分的切片拼成一行文本线,低于阈值的切片把它拆断。scores = [0.9, 0.95, 0.98, 0.92, 0.1, 0.3, 0.88, 0.91, 0.86, 0.2]模拟一条水平文本行上 10 个竖直切片的置信度,中间那两个低分是反光干扰。center = box.mean(axis=0)计算四边形中心,这是向内收缩的“锚点”,每个角点朝中心挪。box + (center - box) * shrink_ratio收缩公式:角点向中心靠拢 shrink_ratio 比例,对应论文里的 Vatti 收缩思想。np.clip(k * (prob_map - threshold_map), -30, 30)先算概率与阈值的差值再乘系数,clip 防止指数爆炸,这是可微二值化的数值稳定技巧。binary_map > 0.5推理阶段把 S 形输出转成 0/1 掩码,再统计面积,对应 DB 的连通域提取前置步骤。
常见误区
误区我看 CTPN 是经典的文字检测模型,以为它和现代检测器一样,横排竖排弯曲的文字都能检测。
正解CTPN 的设计根基是“固定宽度的垂直锚框 + 水平方向的 BLSTM 序列建模”,它把文字当作水平方向上的一串竖直切片。竖排、弯曲的文字在切片之后,相邻切片的上下文彻底失去连续性,检测会崩掉。所以 CTPN 只适合水平或近似水平的文字,比如身份证、车牌、横幅。
为何常见:很多 OCR 教程把 CTPN 当作“文字检测入门模型”来讲,很少强调它只处理水平文字这个硬前提,初学者就容易把它当成万能检测器。
误区我以为 DB 里的“二值化”和传统图像处理一样,阈值是靠经验手动调的固定超参数,比如 0.5。
正解DB 的阈值图 T 是网络的一个分支预测出来的“逐像素阈值地图”,每个位置的阈值都可以不同,而且和概率图一起端到端训练。正是这个可学习的阈值,让 DB 在不同光照、复杂背景下都能自适应贴合文字边缘,而不是靠人手工调参。
为何常见:传统图像处理里二值化阈值确实靠人调,人们容易把旧经验直接套到新模型上,忽略了深度学习中“网络自己学”这个关键差异。
误区我以为 DB 就是把网络输出的概率图在最后阶段做一次二值化,这个操作和训练过程没关系。
正解恰恰相反,普通二值化是阶跃函数,梯度为零,模型无法学习。DB 用 S 形函数近似二值化,训练时梯度能穿过“二值化”这层反向传播,同时优化概率图和阈值图;推理时才是用训练好的模块或固定阈值去取连通域。
为何常见:“二值化”听起来就是个后处理操作,很难联想到它在训练中扮演着“可导层”的角色,这正是 DB 论文最重要的卖点。
误区我以为所有文字检测框都是矩形框,DB 输出的也是四个顶点组成的标准矩形。
正解DB 基于分割,推理时对二值图提取连通域、再做轮廓多边形近似,输出的可以是任意边数的多边形,能贴合弯曲、倾斜的招牌。而 CTPN 因为后处理是“连框 + 边缘细化”,输出更接近水平矩形。这也是 DB 能处理场景文字而 CTPN 不能的根本原因。
为何常见:教科书和论文里常用矩形框示意检测结果,让人误以为所有检测器的输出形式都一样,忽略了分割类方法天然支持任意形状。
面试题
Q1. CTPN 最擅长检测哪种排列方式的文字?
- A.水平排列的文字← 正确答案
- B.竖直排列的文字
- C.任意弯曲的文字
- D.圆形环绕的文字
答案:A。CTPN 用固定宽度的垂直锚框和水平方向的 BLSTM 建模,本质是把文字当作水平方向的一串切片,因此只有水平排列的文字能发挥它的优势。竖排和弯曲文字的切片连续性会被破坏,检测效果骤降。
Q2. CTPN 用于判断文字的基本单元是什么?
- A.整幅图像区域
- B.垂直细长的锚框← 正确答案
- C.完整独立的字符
- D.水平长条窗口
答案:B。CTPN 的核心单元是 16 像素宽的垂直锚框,高度可变。它不先检测完整字符,而是判断每个竖直细条是不是文字的一部分,再把连续细条连成文本线,这就像小切一片一片切吐司检查。
Q3. DB 算法的核心创新点是什么?
- A.引入注意力机制
- B.可微二值化模块← 正确答案
- C.加深网络到百层
- D.使用更大训练集
答案:B。DB 的招牌创新是把不可导的固定阈值二值化替换成可微的 S 形近似,让二值化过程能参与端到端训练。注意力机制、网络深度和训练集规模都不是它区别于其他分割法检测器的本质。
Q4. 关于 DB 的阈值图,下列说法正确的是?
- A.阈值是固定超参数
- B.阈值图由网络预测← 正确答案
- C.阈值图来自人工标注
- D.阈值与训练无关
答案:B。DB 的阈值图 T 是网络的一个分支实时预测出来的逐像素地图,每个位置的阈值都可以不同,并且参与训练。它不是人工标注、不是固定常数,这正是“自适应阈值”的含义。
Q5. 可微二值化中的“可微”主要指什么?
- A.输出结果恒为浮点
- B.二值化函数可求导← 正确答案
- C.模型支持分布式训练
- D.输入图像必须为灰度
答案:B。“可微”指二值化这个函数对输入可求导,梯度能穿过它反向传播,从而同时优化概率图和阈值图。输出是不是浮点、能否分布式训练、输入是否灰度,都和“可微”无关。
Q6. CTPN 网络的输出内容包含哪些?
- A.文本与非文本的置信度← 正确答案
- B.垂直方向的位置偏移← 正确答案
- C.水平方向的边缘细化← 正确答案
- D.像素级的文字概率图
答案:ABC。CTPN 是多任务输出:每个锚框预测文本/非文本分数、垂直坐标偏移和水平边缘偏移。像素级概率图是 DB 这类分割方法的输出,CTPN 不做逐像素预测。
Q7. 关于 CTPN 的文本线构造,下列说法正确的有?
- A.相邻锚框水平距离近← 正确答案
- B.相邻锚框垂直重叠高← 正确答案
- C.直接输出完整矩形框
- D.剔除低置信度锚框← 正确答案
答案:ABD。文本线构造时,先剔除低置信度的锚框,再把“水平距离近且垂直重叠度高”的锚框连成文本线。它不是直接回归完整矩形框,而是先有切片拼接、再做边缘细化,C 的说法违背了 CTPN 的设计逻辑。
Q8. Vatti 收缩算法生成训练标签时,收缩距离 d 与什么有关?
- A.只与图像宽度有关
- B.只与文字颜色有关
- C.面积与周长共同决定← 正确答案
- D.与人眼识别能力有关
答案:C。收缩距离 d = A(1−r²)/L,由多边形面积 A 和周长 L 共同决定。面积越大收缩尺度越大,周长越长(形状越细长)收缩距离越小,防止细字被缩没。与图像宽度、颜色都无关。
Q9. DB 在训练阶段的损失函数由哪些部分组成?
- A.概率图二分类损失← 正确答案
- B.二值图二分类损失← 正确答案
- C.阈值图的 L1 损失← 正确答案
- D.字符识别的交叉熵
答案:ABC。DB 总损失 = 概率图损失 + 二值图损失 + 阈值图 L1 损失,前两项用带难样本挖掘的 BCE,阈值图用 L1。DB 只做检测不做字符识别,因此没有字符识别的交叉熵项。
Q10. DB 可微二值化系数 k 增大时,下列哪个效果会增强?
- A.S形曲线变得更陡峭← 正确答案
- B.阈值图数值会变大
- C.特征图分辨率提高
- D.文字区域自动扩大
答案:A。k 是二值化曲线 1/(1+e^{−k(P−T)}) 的放大系数,k 越大曲线越陡峭、越接近真正的阶跃二值化。但 k 过大会导致梯度消失,训练不稳定。k 不参与阈值图的数值大小,也不影响分辨率或区域面积。