一、引言:OCR不是一个算法,而是一条算法流水线
“OCR文字识别用的是什么算法?”这是几乎所有初学者接触OCR时都会提出的问题。标准答案远比想象中复杂:现代OCR系统从来不是某个单一算法的产物,而是一条由图像预处理、文本检测、文本识别、后处理与结构化还原等多个环节组成的算法流水线。每个环节都有各自独立的模型结构与经典算法,理解这条流水线,才能真正理解OCR的能力边界与优化方向。
以“PDF转Markdown”这类文档解析场景为例:系统不仅要“认字”,还要判断哪一段是标题、哪一块是表格、阅读顺序如何排列。这决定了现代OCR的算法栈需要同时具备“感知”与“理解”两层能力。
二、总体技术框架:检测与识别的两阶段范式
主流OCR方案遵循“先检测、后识别”的两阶段范式:
原始图像 → 预处理 → 文本检测(定位)→ 文本识别(转文字)→ 后处理/结构化 → 输出
- 文本检测回答“字在哪里”:在图像中定位所有文字区域,输出矩形或多边形坐标框;
- 文本识别回答“是什么字”:将裁剪出的文字条目送入序列模型,输出字符序列;
- 结构化还原回答“这些字如何组织”:面向文档解析场景,恢复标题层级、表格拓扑与阅读顺序。
此外还存在端到端范式(一次前向传播同时完成检测与识别),推理速度更快,但两阶段范式在精度可控性、环节可调试性方面优势明显,仍是工业界的主流选择。
三、图像预处理:决定识别上限的第一道工序
预处理常被新手忽视,却直接决定下游模型的表现上限:
- 灰度化与二值化:全局阈值法(如Otsu大津法,按类间方差最大化自动选阈值)适合光照均匀的印刷件;自适应阈值按局部邻域计算,适合光照不均的扫描件与拍照件。
- 去噪:高斯滤波、中值滤波与形态学开闭运算,可去除扫描噪点、装订线阴影和背景污渍。
- 倾斜矫正:通过霍夫变换或轻量角度预测网络估计倾斜角,再用仿射或透视变换拉正页面。倾斜2度以上就会显著拉低识别准确率。
- 分辨率控制:扫描建议300DPI。过低会导致笔画断裂、小字模糊;过高则浪费算力与显存。
工程实践中大量“识别不准”的问题,追根溯源都是预处理环节没有做好。
四、文本检测算法:先找到“字在哪”
- 传统方法:连通域分析与MSER(最大稳定极值区域)适合背景干净的印刷文档,计算开销小,但对复杂背景、光照变化鲁棒性差。
- 基于锚框回归:CTPN在通用目标检测框架基础上引入垂直锚点与双向序列建模,擅长定位水平排列的长文本行;EAST等则直接回归任意旋转文本框。
- 基于分割的DB(可微二值化):目前工业界应用最广的思路。它将检测建模为像素级分类问题,预测文字概率图;核心创新在于训练阶段用可微分的二值化近似替代不可微的标准二值化操作,把阈值变成可学习参数,缓解了边缘像素梯度消失问题。推理时从概率图轮廓提取多边形文字框,天然支持倾斜、弯曲文本。
检测模型的骨干通常是通用视觉骨干网络(如残差网络)加特征金字塔颈部结构,兼顾大版面中的小字号文本与超大标题。
五、文本识别算法:再回答“是什么字”
- 早期方案:单字符切割+分类。致命缺陷是切割错误会沿流程向后传播,且对连笔、字符粘连完全无能为力。
- CRNN(CNN+RNN+CTC):将识别转化为序列学习问题。卷积网络把文字条目编码为特征序列,双向循环网络建模上下文依赖(利用“前后文字互相印证”的语言规律),最后由CTC解码输出序列。最大优点是无需字符级标注、推理速度快,至今仍是性价比极高的方案。
- CTC原理简述:引入空白占位符号,通过动态规划枚举输入帧与输出标签之间的所有可能对齐路径并求概率之和。通俗地讲:它不关心“每一帧预测了什么”,只关心“整条序列合并去重后最终是什么”,从而绕开了字符逐帧对齐这一不可能完成的标注任务。
- 注意力编解码:编码器-解码器架构,解码时对特征图不同区域施加注意力权重。精度上限更高,但长文本训练存在注意力漂移问题,推理速度也偏慢。
- 纯Transformer结构:以SVTR为代表,用全局自注意力替代循环结构,在保持推理效率的同时取得更高识别精度,是新一代主流演进方向。
中文识别的特殊挑战在于:字符集庞大(通用模型需覆盖数千常用汉字)、形近字多(如“己/已/巳”)、中英文与数字混排。工程上通常依靠扩大字符表、数据增广与语言模型纠错来缓解。
六、版面分析与结构化:从“认字”到“懂文档”
对PDF转Markdown这类任务,难点已不在识别,而在文档理解:
- 版面分析:本质是目标检测/语义分割任务,将页面划分为标题、正文、表格、图片、页眉页脚等语义区域,通常由通用检测架构实现;
- 表格结构识别:先检测单元格,再通过行列空间关系推理还原表格拓扑,输出HTML或Markdown表格;
- 阅读顺序恢复:对各版面区域的空间坐标做拓扑排序,正确处理多栏、跨栏、跨页等复杂情况;
- 公式等特殊元素:可引入专门的序列到序列模型单独处理。
七、工程实践:算力选择与部署避坑
算法之外,落地时的算力问题同样关键,以下为典型工程经验:
- CPU与GPU的取舍:CPU适合轻量体验与临时任务;批量处理或含大量表格、复杂排版的文档时,CPU算力会成为瓶颈,GPU通常可带来5-10倍的速度提升,等待焦虑显著降低。
- 显存估算:检测+识别+版面分析的模型组合,加载约占用2.4GB左右显存;处理高分辨率复杂文档时峰值可达6GB上下。显存低于4GB的设备在批量处理时容易出现显存溢出(OOM),建议降低并发或直接使用CPU推理。
- 版本兼容:GPU并行计算运行时与显卡驱动、框架编译版本需严格匹配;较新架构的显卡可能因算子尚未充分验证而暂时不稳定,选型优先考虑经过验证的主流架构。
- 服务化细节:首次启动需从本地加载体积较大的模型文件,耗时较长属正常现象;本地Web服务若启动后浏览器未自动打开,先检查终端是否提示端口(如7860)被占用;大文件处理闪退多为OOM,可通过减少并发数、分页处理、失败时自动降级CPU等策略规避。
# OCR 两阶段流水线伪代码page = preprocess(load("document.pdf")) # 二值化 / 去噪 / 矫正regions = layout_analyzer(page) # 版面分析:标题/正文/表格for region in regions: boxes = text_detector(region.image) # 检测:文字在哪里 texts = [recognizer(crop(region.image, b)) for b in boxes] region.text = merge_by_reading_order(boxes, texts)markdown = structure_restore(regions) # 输出 Markdown
八、算法选型与落地建议
- 场景匹配:清晰印刷件对算法要求最低;自然场景(拍照、复杂背景)需要更强的检测与识别模型;手写体难度最高,往往还需语言模型后纠错;
- 精度与速度权衡:通过模型裁剪、INT8量化、知识蒸馏,可在精度损失可控的前提下大幅提速,适合边缘设备与高并发场景;
- 自建与云服务的取舍:追求快速接入与免运维,可选用百度智能云等提供的通用文字识别类云服务能力;对数据隐私、定制字符表、离线部署有强需求的,则基于开源框架自建流水线更合适。两条路线并不互斥,实践中常按业务敏感度分层混用。
九、结语
回到最初的问题——“OCR文字识别用的是什么算法?”答案可以浓缩为一句话:用预处理算法把图变干净,用分割式检测算法找到字,用CRNN/CTC或Transformer类序列模型认出字,再用版面分析算法把字组织成结构。每个环节仍在持续演进,多模态大模型也正在把“感知+理解”融合为一体化能力。对开发者而言,理解这条算法链路的真正价值在于:识别不准时知道往哪个环节排查,做性能优化时知道瓶颈在哪,做技术选型时知道每种方案的适用边界。