OCR 这个领域,我用过不少开源方案,说实话能真正做到“开箱即用”的没几个。EasyOCR 是其中一个让我觉得省心的工具——装好库、下载模型、两行代码出结果,从图片里把文字抠出来,就这么直接。它不是那种只能跑通 Demo 的花架子,日常处理证件、截图、票据都能用,而且对中文、英文、数字混合场景的支持做得比很多老牌方案更省事。这篇文章我就把 EasyOCR 从原理到实战捋一遍,适合刚接触 OCR 的开发者,也适合已经在用 Tesseract 想换方案的朋友参考。
我最早接触 EasyOCR 是在一个模拟项目 X 里,领导要求快速把一批扫描件里的编号和金额提取出来。当时我第一反应是用传统方案,结果图片质量参差不齐,处理起来极其痛苦。换了 EasyOCR 之后,整个流程瞬间清爽了。它背后用的是深度学习模型,对倾斜、模糊、复杂背景的容忍度比普通工具高一大截。更重要的是,它把所有模型都打包进了开源库里,用户不需要懂训练流程,安装完就能直接推理,这是“开箱即用”的真正含义。
这篇文章不会只贴着官网文档念参数,我会把我实际踩过的坑、各种参数在真实图片上的表现、以及批量处理时容易忽略的细节都写出来。你看到的所有建议,都是我跑过真实图片后沉淀下来的经验。读完你应该能独立搭一套 OCR 服务,至少能应付日常百分之八十的识别需求。
1. 项目概述与定位
涉及一个工具,第一件事就是搞清楚它到底解决了什么问题,什么时候该选它。EasyOCR 不是什么万能识别神器,它有自己的适用边界,但在这个边界内,它确实做得足够出色。
1.1 EasyOCR 到底解决什么问题
简单说,EasyOCR 是一个基于深度学习的开源光学字符识别工具,它读取图片,检测其中包含文字的区域,然后识别出具体的字符内容。所谓“开箱即用”,意思是安装之后不需要准备任何额外训练数据或模型文件,程序会自动下载一套预训练好的权重,直接可以跑出结果。
我常用它来处理三类事情:第一类是把截图里的文字提取成可编辑文本;第二类是识别扫描件中的固定字段,比如发票号码、合同编号;第三类是做一些轻量级的自动化存档工作,比如把纸质文档拍照后自动归类。这三类事情如果用传统 OCR 方案做,前置处理很重,但用 EasyOCR 基本是省心的。
需要特别指出的是,EasyOCR 更适合做“通用识别”。它不像某些商业 API 那样针对特定证件做了极致优化,但胜在灵活、离线可用、没有调用次数限制。如果你需要专精识别一类极其特殊的图片,比如切割过的验证码、艺术字体,那还是得考虑专门的模型或服务。
1.2 和其他 OCR 工具的核心差异
很多人第一次听到 EasyOCR,会拿它和另一个老牌开源工具做比较。两者都能做 OCR,但思路差别很大。传统工具依赖图像处理流程做字符切割和模板匹配,对图片质量要求高,遇到复杂背景、低分辨率、弯曲文字时效果不稳定。EasyOCR 直接使用神经网络做端到端的文字检测和识别,等于把“人眼找字”这个步骤交给了模型,天然更抗干扰。
EasyOCR 对语言的扩展也做得很好。它支持 80 多种语言的识别,其中中文简体、中文繁体、英文、日文、韩文这些都是开箱即用的主流语言。如果项目中遇到多语言混合场景,传统方案通常需要分别配置语言包,而 EasyOCR 在初始化时传入语言列表就能同时识别,这是很大的优势。
另一个差异在于输出格式。EasyOCR 的识别结果默认包含文字内容和对应的坐标框,这一点对后续要做版面分析、区域过滤的人特别友好。拿坐标框去定位关键词,再提取后续内容,可以做出相当灵活的规则引擎,而不是傻傻地把整页文字塞进正则表达式里。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心原理:它凭什么能“开箱即用”
用工具是一回事,理解它背后的原理是另一回事。只有理解了检测和识别是如何分工的,你在调参时才不会两眼一抹黑。
2.1 OCR 流水线拆解:检测与识别
现代 OCR 开源工具几乎都是“两阶段”结构,EasyOCR 也不例外。第一阶段是文字检测,它会在输入图片上找出所有“看起来像文字”的区域,画出一堆候选框来。第二阶段是文字识别,它把检测到的每个区域单独拉出来,转成对应的字符串,比如“ABC123”或者“你好世界”。
这两个阶段是串行发生的。检测阶段漏掉一个区域,识别阶段就根本不知道那里有字。所以你会发现很多识别不准的场景,问题往往出在检测环节,而不是识别环节。比如字体太小、背景复杂、文字旋转,都会让检测模型丢失目标。
理解了这个过程,你就明白为什么图像预处理这么重要。检测模型对输入图像的清晰度、对比度、尺寸是有隐含要求的。如果原图分辨率过低,可以先把图片放大再送进去,识别率通常会提升不少。这比调任何识别参数都更直接。
2.2 检测端与识别端的模型细节
EasyOCR 的检测模型采用了行业内非常经典的 CRAFT 思路。CRAFT 的核心是逐字检测,它会先找出每个字符的中心区域,再把这些字符区域通过链接关系聚合成完整的单词或文本行。这种做法的好处是,即使文字是倾斜的、弯曲的,只要字符本身能被发现,最终也能拼出完整的行来。
识别模型通常采用 CRNN 的组合结构,也就是卷积网络提取图像特征,循环网络捕捉序列信息,再通过连接时序分类输出结果。这个结构相当于先让模型“看一眼”整张字符图片,再按时间顺序一个字符一个字符地输出来。实际推理时,EasyOCR 还支持普通解码和 beam search 解码,后者在识别长句子时通常会稍微稳定一点,但速度会慢一些。
值得一提的是,EasyOCR 会在网络模型之后接一个语言模型层面的解码逻辑。它不仅仅依赖视觉特征,还会结合字符的上下文概率。当你识别一段连续文字时,这个机制能纠正一些单字看不清的情况,让最终结果更符合真实语言习惯。
2.3 模型权重与缓存机制
所谓的“开箱即用”,核心秘密在于预训练权重。你在初始化 Reader 时,EasyOCR 会检查本地缓存,如果没有找到对应语言的模型文件,就会自动从项目仓库下载。这个下载过程通常只需要一次,之后每次调用都会直接使用缓存。
默认情况下,模型文件会存放在用户目录下的一个隐藏文件夹中。但在服务器部署时,我强烈建议你指定一个独立目录,方便管理模型文件,避免不同环境之间相互干扰。你可以通过 model_storage_directory 参数来指定路径。这样离线部署时也容易处理,只需要把模型文件提前拷到目标机器的对应目录即可。
有一点需要提醒:如果你更换了 EasyOCR 版本,它可能要求重新下载模型,因为新旧版本的模型结构可能不兼容。我遇到过升级后模型不匹配导致推理报错的情况,所以生产环境里我一般会固定版本号,非必要不升级。
3. 环境准备与快速安装
这一节给新手上路提供完整的安装指引,也会列出一些我实际踩过的坑。
3.1 运行环境清单
EasyOCR 本质上是 PyTorch 应用,所以安装前必须先有 Python 环境。建议使用 Python 3.8 到 3.11 之间的版本,太新或者太旧都可能遇到依赖不兼容的问题。在目标准生产环境里,我用 3.9 比较多,稳定性好,踩坑少。
依赖方面,最核心的是 PyTorch 和 torchvision。CPU 环境直接安装 CPU 版 PyTorch 就够,GPU 环境则要安装对应 CUDA 版本的 PyTorch。这个决定会影响后续识别速度,但不是必需条件。没有 NVIDIA 显卡的朋友完全不用担心,EasyOCR 在 CPU 上也能跑,只是速度会慢一些。
我列一个最简单的环境参考:
| 组件 | 推荐配置 | 说明 |
|---|---|---|
| 操作系统 | Windows / Linux / macOS | 只要 Python 能装,基本都能跑 |
| Python | 3.8 ~ 3.11 | 太老缺少依赖,太新容易踩坑 |
| PyTorch | CPU 版或 CUDA 版 | 有 GPU 就装对应版本 |
| 内存 | 最低 4GB,推荐 8GB+ | 加载模型需要一定内存 |
| 磁盘 | 预留 1GB 空间 | 模型文件通常几百 MB |
3.2 pip 安装与常见坑
安装命令其实很透明,直接执行下面的命令就行:
bash复制pip install easyocr
但真实安装过程往往不会一帆风顺。最常见的坑是 PyTorch 默认下载慢,导致整个安装过程卡在“Downloading”界面久久没有响应。解决办法是提前独立安装 PyTorch,并指定国内镜像源。用清华源,命令大概是这样的:
bash复制pip install torch torchvision -i https://pypi.tuna.tsinghua.edu.cn/simple
安装好 PyTorch 之后,再继续安装 EasyOCR,此时它检测到 PyTorch 已存在,就不会强行重复下载大体积依赖了。另外,EasyOCR 依赖 opencv-python,有些环境里系统自带了精简版 OpenCV,可能会有冲突。遇到导入报错时,可以考虑额外安装 opencv-python-headless 来替换,两者选一个就行。
我在某次部署到容器环境时,还遇到过缺少系统库的问题,比如 libgl1 和 libgomp1。这种属于操作系统层面的依赖,安装命令会提示得很直白,按照提示补上即可。
3.3 预训练模型的获取与离线部署
首次初始化 Reader 时,EasyOCR 会自动下载模型文件。如果你是在有网环境下的开发机,这一步不会有什么问题。但生产环境常常是内网隔离的,这时候就要手动传输模型文件。
我通常会在开发机上先运行一次初始化代码,让它把模型完整下载到指定目录,然后把整个模型目录整个拷贝到生产机。代码里指定同一个目录即可:
python复制import easyocr
reader = easyocr.Reader(['ch_sim', 'en'], model_storage_directory='/data/easyocr_models', download_enabled=False)
download_enabled=False 这个参数很关键,它告诉 EasyOCR 不要企图联网下载模型。如果生产机上对应目录没有模型文件,程序就会直接报错,这比网络请求超时更好排查。我第一次做离线部署时没关这个开关,结果程序每次启动都先去尝试联网,白等几十分钟才超时。
模型目录里你会看到检测模型和识别模型两类文件。细究可能有多个,比如中文简体、英文各一个识别模型。备份时要把整个目录都拷走,不要只拷其中一个文件。
4. 实战:第一次完整跑通
这一节我们从零写代码,把一张图片里的文字提取出来,同时把结果的含义讲清楚。代码很短,但里面的信息量很足。
4.1 从图像到字符串的完整示例
假设你有一张名为 sample.jpg 的图片,里面有中英文混合的文字。我们要识别它,只需要三行核心代码:
python复制import easyocr
reader = easyocr.Reader(['ch_sim', 'en'], gpu=True)
result = reader.readtext('sample.jpg')
for bbox, text, conf in result:
print(text, conf)
第一次执行时,控制台会输出模型加载信息,然后开始推理。CPU 环境下可能稍微等几秒,GPU 环境下通常瞬间出结果。打印出来的每一行就是识别出的文字和对应的置信度。
这里有一个细节:Reader(['ch_sim', 'en']) 传入的列表表示要加载的语言。顺序无所谓,但每种语言都会对应一个模型文件。如果你只需要识别英文,只传 ['en'] 就行,加载速度会更快。识别中文时要注意传 'ch_sim' 而不是 'ch',繁体场景则传 'ch_tra'。
4.2 输出结果结构详解
readtext 默认返回一个列表,每个元素是一个三元组。第一项是坐标框,第二项是识别出的文本,第三项是置信度。坐标框是一个包含四个点的列表,每个点又包含 x 和 y 坐标,顺序依次是左上、右上、右下、左下。
这个坐标信息非常有用。例如你想提取发票上的号码,但整页有很多文字,你完全可以用坐标把图片分区,只识别某个区域,减少干扰。最简单的做法是判断坐标中心点是否在目标矩形范围内,仅保留落在区域内的文本。
置信度是 0 到 1 之间的浮点数。0.9 以上通常说明识别得很扎实,0.5 以下就值得怀疑。我一般在业务逻辑里设置一个阈值,比如低于 0.4 的结果直接丢弃,避免把噪声文本当成有效内容。
如果你只想拿字符串,不关心坐标,可以这样写:
python复制texts = reader.readtext('sample.jpg', detail=0)
print(texts)
这样返回的就只是一个字符串列表。但如果要做后续区域过滤,还是要保留带坐标的结果。
4.3 用参数提升识别率:那些被忽略的旋钮
很多人只会用默认参数,但实际上 EasyOCR 的 readtext 提供了很多调节项。最常用的是 text_threshold、low_text 和 link_threshold。这三个参数控制检测阶段提取文字区域的敏感度。
text_threshold 默认 0.7,数值越低越容易把某些模糊区域认定为文字。如果你的图片文字不清,适当降到 0.5 左右可能会有惊喜。low_text 默认 0.4,它控制低置信度文字的局部保留程度。link_threshold 默认 0.4,它控制相邻字符是否被连成一个整体。倾斜排列的文字可以适当调低它,让字符更容易聚合。
还有两个参数对结果影响很大:mag_ratio 和 canvas_size。mag_ratio 是图像放大系数,它决定了检测模型看到的图像尺寸。小图片识别不好时,可以把 mag_ratio 调到 2 甚至 3,识别率会明显上升。canvas_size 是模型输入的最大边尺寸,对于超高清大图可以适当调大,避免文字因为过度压缩而丢失。
python复制result = reader.readtext('sample.jpg', text_threshold=0.6, low_text=0.3, link_threshold=0.3, mag_ratio=2.0)
调参没有万能公式,不同的图片类型需要微调。我建议拿着三五张有代表性的图反复试,找到一组泛化能力最好的参数再用到批量任务里。这个探索过程很值得投入,因为默认参数不一定是最优的。
5. 进阶实操:批量处理与结构化输出
把单张图跑通只是第一步,实际项目里很少只处理一张图片。这一节我会讲批量识别的实战写法,以及如何把 OCR 结果变成可用的结构化数据。
5.1 批量识别一组图片并保存结果
批量识别的思路很简单:遍历文件列表,逐张调用 readtext。但如果图片数量多,一次性全部读进内存会很浪费资源,最好逐张处理,并把结果及时保存,避免中途崩溃丢数据。
下面这个例子是读取指定目录下所有 .jpg 和 .png 图片,把每张图的识别文本写入同名文本文件:
python复制import easyocr
import os
reader = easyocr.Reader(['ch_sim', 'en'], gpu=True)
input_dir = './images'
output_dir = './output'
os.makedirs(output_dir, exist_ok=True)
for filename in os.listdir(input_dir):
if not filename.lower().endswith(('.jpg', '.png', '.jpeg')):
continue
path = os.path.join(input_dir, filename)
result = reader.readtext(path, detail=0)
out_path = os.path.join(output_dir, os.path.splitext(filename)[0] + '.txt')
with open(out_path, 'w', encoding='utf-8') as f:
f.write('\n'.join(result))
print(f'处理完成: {filename}')
这段代码看起来简单,但它把“逐条识别”和“断点续存”的思想落地了。我在实际项目中还会加入 try/except,把单张图片失败的情况记录下来,继续处理后面的图片:
python复制for filename in os.listdir(input_dir):
...
try:
result = reader.readtext(path, detail=0)
except Exception as e:
print(f'识别失败: {filename}, 错误: {e}')
continue
这样即使遇到个别损坏图片,也不会让整个批次停摆。
5.2 用坐标信息做区域级过滤
批量跑完,你会发现识别出了很多不想要的文字,比如背景里的水印、角落里的版权信息。这时候坐标过滤就派上用场了。假设你只关心图像中央区域的文字,可以这样过滤:
python复制result = reader.readtext('page.jpg')
def in_region(bbox, x1, y1, x2, y2):
xs = [p[0] for p in bbox]
ys = [p[1] for p in bbox]
cx = sum(xs) / len(xs)
cy = sum(ys) / len(ys)
return x1 <= cx <= x2 and y1 <= cy <= y2
filtered = []
for bbox, text, conf in result:
if in_region(bbox, 100, 50, 500, 300):
filtered.append((text, conf))
这是一种非常实用的“局部提字”思路。比如扫描件下方通常有页码和日期,你不想让它干扰主内容提取,只要把目标区域框出来,问题就解决了。
5.3 结合正则表达式提取关键字段
OCR 识别结果本质上是一堆字符串,要从里面提取结构化字段,用正则表达式是最直接的手段。比如识别出来的文本是:
text复制发票号码: 1234567890
开票日期: 2025-01-15
金额: ¥1234.56
我们可以这样提取:
python复制import re
texts = reader.readtext('invoice.jpg', detail=0)
full_text = '\n'.join(texts)
def extract(pattern, text):
match = re.search(pattern, text)
return match.group(1) if match else None
invoice_no = extract(r'发票号码[::]\s*(\w+)', full_text)
date = extract(r'开票日期[::]\s*(\d{4}-\d{2}-\d{2})', full_text)
amount = extract(r'金额[::]\s*[¥¥]\s*([\d,.]+)', full_text)
print(invoice_no, date, amount)
用这种组合拳方式提取字段,比用一个宏大模型做端到端信息抽取要务实得多。关键是先保证 OCR 文字质量,再用正则精确匹配。如果 OCR 偶尔把“8”识别成“B”,那就要结合字段的规则长度后再做后处理,比如去掉非数字字符。
下面这个例子是常见的清洗函数:
python复制invoices = re.search(r'发票号码[::]\s*([0-9A-Za-z]+)', full_text, re.I)
if invoices:
raw = invoices.group(1)
cleaned = re.sub(r'[^0-9A-Za-z]', '', raw)
print(cleaned)
6. 性能与精度调优实录
这一节聊的是真实项目里迟早会遇到的问题:怎么让识别更快、更准。没有一劳永逸的答案,但有几条经验能帮你少走弯路。
6.1 CPU 与 GPU 环境下的性能对比
EasyOCR 是深度学习模型,GPU 的并行计算能力对速度提升非常明显。实测同样的图片集,CPU 环境下每张可能要 1 到 3 秒,GPU 环境下往往不到 0.1 秒,差距可以达到十倍以上。如果你有批量识别需求,且手头有可用 GPU,尽量启用 GPU 推理。
启用方式就是在初始化 Reader 时设置 gpu=True。如果电脑实际上没有可用 GPU,程序会抛错或者自动回退。更稳妥的写法是先用 PyTorch 检测一下:
python复制import torch
print(torch.cuda.is_available())
然后在代码里根据检测结果设置 gpu 参数:
python复制reader = easyocr.Reader(['ch_sim', 'en'], gpu=torch.cuda.is_available())
这里有个小技巧:GPU 模式下,readtext 支持 batch_size 参数,可以把多张图片合并成一个批次推理,吞吐量更高。不过要注意显存有限,batch_size 设为 4 可能就已经很吃显存了。如果显存不足,减小图片尺寸或者调低 canvas_size。
6.2 图像预处理三板斧
在把图片交给 EasyOCR 之前,自己先做点预处理,往往比调 EasyOCR 参数更有效。第一板斧是放大。小图识别容易漏字,把图片长边放大到 2000px 以上再识别,检测模型更容易找到细小文字。
第二板斧是提升对比度。OCR 比较怕灰蒙蒙的图片,用 OpenCV 的 convertScaleAbs 或直方图均衡化可以让文字和背景分离度更高。不是所有图都需要这一步,但对老旧的扫描件特别有效。
python复制import cv2
img = cv2.imread('sample.jpg')
img = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
第三板斧是去噪。图片里的噪点会让检测模型产生误判,可以用 cv2.fastNlMeansDenoisingColored 去噪,或者做一次轻微的高斯模糊。注意别把文字本身弄糊了,模糊核要小。
预处理之后,把处理好的图像保存在临时文件再传给 EasyOCR,或者直接传入 numpy 数组,两者都支持。我更喜欢传数组,因为少一次磁盘读写。
6.3 模型选择与语言扩展
EasyOCR 的模型文件是针对特定语言训练的。中文简体、中文繁体、英文、日文、韩文这些模型,质量都还可以。但如果你遇到的图片是小语种,识别效果就可能不太理想,因为训练数据本身就少。
这时候有两条路。第一条是调整语言组合。比如识别泰文时,可以同时加载英文模型辅助识别,因为泰文文本里经常夹杂阿拉伯数字。第二条是使用自定义模型接口,把 EasyOCR 作为一个基础组件,接入自己微调过的模型权重。这条路对普通开发者来说门槛偏高,但设计上确实留了接口。
关于语言扩展,我补充一个操作:如果你想了解目前支持哪些语言,可以打印 reader.lang_char 或查看官方文档列表。实际使用中不要盲目加载大量语言,每多一种语言就多一个模型文件,内存占用和加载时间都会增加。
7. 常见问题与排查手册
这里我整理了使用过程中最容易踩的坑,用一张速查表放在前面,再看后面具体展开。
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 安装慢或安装失败 | PyTorch 下载慢、系统库缺失 | 先装 PyTorch,换镜像源,补系统依赖 |
| 首次运行卡在下载 | 网络问题 | 手动下载模型,放到指定目录 |
| 识别不出中文 | 语言参数传错 | 使用 ch_sim,不要用 ch |
| 识别结果乱码 | 图片分辨率低、文字模糊 | 放大图片,调整 mag_ratio |
| 显存不足 | batch_size 太大、图太大 | 减小 batch_size,调整 canvas_size |
| 维护升级后模型报错 | 模型与新版本不兼容 | 固定版本号,或重新下载模型 |
7.1 安装与启动问题
很多朋友一上来就 pip install easyocr,然后卡半天没有反应。这往往是 PyTorch 安装导致的超时。我的建议是先把 PyTorch 单独装上。装 PyTorch 时,在有 GPU 的环境里,最好去 PyTorch 官网找到对应的 CUDA 版本安装命令,直接用 pip 指定 --index-url。
还有一种情况是安装成功了,但 import easyocr 时报错找不到某个共享库。这类报错几乎都出在 OpenCV 上。你可以在安装完 EasyOCR 后再执行一遍 pip install opencv-python-headless,用无图形界面版本代替带 GUI 的版本,能避开大部分服务器环境的图形库问题。
7.2 识别结果错乱或漏字
这个问题的原因很杂,但我遇到最多的是图片过小。文字在小图里只有十几个像素高,别说机器,人眼看着都费劲。这时候用放大镜参数 mag_ratio=2.0 或者直接把图片裁出来放大,效果立竿见影。
还有一个常见原因是文字倾斜角度过大。EasyOCR 对小幅倾斜是能处理的,但超过四十五度就很容易失败。可以先做旋转校正,把图片摆正再传给 EasyOCR。旋转思路很简单,先用检测坐标算出一个大致的偏转角度,再用 OpenCV 旋转回来。这个后处理我在一个票据项目里用过,识别成功率从不到五成提到了八成以上。
7.3 CUDA 相关报错
CUDA 报错最容易让人抓狂,因为它经常出现在环境配置无误、“应该能跑”的情况下。最常见的是显存不足,程序报一个看似随机的分配错误。解决办法是把 batch_size 调到 1,同时把 canvas_size 适当调小,减少峰值显存占用。
如果报错信息里提到算力不匹配,说明当前 PyTorch 版本对应的 CUDA 和你电脑驱动支持的 CUDA 不一致。这种情况往往是 PyTorch 装错了版本,需要卸载重装。CPU 机器上如果强行 gpu=True 也会报错,可以用 torch.cuda.is_available() 做判断。
8. 一些个人体会
EasyOCR 不是完美的工具,我见过它对艺术字体的识别表现相当一般,也见过它在一块纯色背景上突然漏掉一个数字。但作为开源方案,它的性价比已经足够高。在多数业务场景里,配合好预处理和后处理,它完全能落地成一套稳定可用的识别服务。
我在多次项目中总结出一个重要经验:不要为了追求“极致准确率”过度调参。OCR 的结果天然就有不确定性,与其死磕模型参数,不如在业务层做好校验和容错。比如提取发票号时,计算一下校验位是否符合规则,这样就能把大多数识别错误挡在外面。工具的能力和业务规则结合起来,才是真正可靠的做法。
最后再分享一个小技巧:如果发现某些图片怎么调参数都识别不好,退一步看,把图片裁剪成更小的区域再识别,效果常常会好很多。让模型一次只看一部分,比强迫它在整个大图里找文字要稳定得多。这个思路贯穿了我整个 OCR 项目周期,也推荐你自己试一次。
