8 种条件 4 段文字,944 个字逐字对过

我以为抠字是个小活

拍张纸,把上面的字变成能复制的文本。这件事现在被说得太轻了。

可我用下来,同一张图,两个引擎给出的东西能差出一条街。

一个把「31.5」读成「315」,小数点没了。另一个把整行字读对了,顺序全颠倒,最后一句跑到最前面。

所以这篇不吹谁强。我把两个引擎拉到同一批图上,一个字一个字对。

一辆挂着 1938 年加州车牌的老车。现实里的字印在金属曲面上,比实验用的渲染图难认
一辆挂着 1938 年加州车牌的老车。现实里的字印在金属曲面上,比实验用的渲染图难认

一、怎么测的

四段文字,都是我编的日常场景,含价格、日期、电话、落款。

1 这个接口每百万 token 收两块钱,发一篇稿子要用掉八千个。 2 昨天下午三点二十,超市里那块五花肉的价签从 28.9 变成了 31.5。 3 客服说系统升级,让我等 48 小时再打电话过去问一次进度。 4 第 7 号楼的电梯停了两天,物业贴了张纸,落款是 10 月 18 日。

四段一共 118 个字。

每段生成 8 个版本,一共 32 张图:

干净 24px 黑体 14px 宋体 12px 微软雅黑 24px 缩到 60% 高斯模糊 0.9 旋转 1.5 度 JPEG 质量 38 灰字压灰底

两个引擎:

RapidOCR rapidocr_onnxruntime,onnxruntime 1.31.0,只有 CPU 提供者 Windows OCR Windows.Media.Ocr,语言包 zh-Hans-CN

比对用编辑距离,把识别结果和真值逐字对。插入、删除、替换都算一次错。空格和全角半角先归一化,不然标点会白扣分。

118 个字乘以 8 组,一共 944 个字次。

二、总分

条件 字数 RapidOCR Windows OCR 干净 24px 118 3 错 2.54% 1 错 0.85% 14px 宋体 118 2 错 1.69% 40 错 33.90% 12px 雅黑 118 0 错 0.00% 23 错 19.49% 缩到 60% 118 3 错 2.54% 4 错 3.39% 高斯模糊 118 5 错 4.24% 2 错 1.69% 旋转 1.5 度 118 24 错 20.34% 2 错 1.69% JPEG q38 118 3 错 2.54% 1 错 0.85% 灰字灰底 118 5 错 4.24% 1 错 0.85% ------------------------------------------------------ 合计 944 45 错 4.77% 74 错 7.84%

总账 RapidOCR 赢。

但这个总账没什么用。因为把表竖着看,两个引擎各有一块地彻底翻车。

还有一个数更值得看:32 张图里,一个字都没错的,RapidOCR 13 张,Windows 18 张。

Windows 全对的张数更多,总错字却更多。意思是它平时挺稳,一旦崩就崩得很难看。

三、小字:Windows 崩了

14px 宋体这一组,Windows 错了 40 个字,占三分之一。

它实际读出来的是这样:

真值 这个接口每百万 token 收两块钱,发一篇稿子要用掉八千个。 识别 这个接囗每白h牧两块钱,发一篇福子要用掉烈千个。

「口」变成「囗」,「稿」变成「福」,「八」变成「烈」,还凭空冒出一个「h」。

12px 微软雅黑一样,错了 23 个字。

同一个条件下,RapidOCR 12px 那张,一个字没错。

小字这块,RapidOCR 赢得干净。

它走的是先检测文字框、再逐框识别的路子,两段模型。小字号下它具体做了什么处理,我没去看源码,也不清楚它内部有没有放大。我只能说这个条件下它没出错,为什么没出错,我不知道。

四、歪一度半:反过来了

旋转 1.5 度,RapidOCR 错了 24 个字。

它读出来是这样:

真值 昨天下午三点二十,超市里那块五花肉的价签从 28.9 变成了 31.5。 识别 31.5。昨天下午三点二十,超市里那块五花肉的价签从28.9变成了

字基本都对,位置全乱。最后一句被搬到了最前面。

原因我猜是这样:图一歪,检测框切成两段,拼回来的顺序反了。这只是猜的,我没看源码验证,也没做可视化的框位置对照。

Windows 在这种图上只错 2 个字。它认行序更抗歪。

所以不是「谁准」的问题,是「你的图会怎么坏」的问题。扫平正的截图,和拍歪的纸,坏的路径不一样。

五、错字都长什么样

把 32 张图的差异全列出来,高频的错法有这么几种。

RapidOCR 这边,主要是多字和少字:

插了个「起」 超市里 -> 起超市里 出现 5 次 插了个「3」 31.5 -> 331.5 出现 4 次 句号变逗号 。 -> , 出现 2 次 句号吞掉 。 -> 空 出现 2 次 插了个「物」 物业 -> 物物业 出现 2 次 重复一个字 让我等 -> 让我等等

Windows 这边,是字形认错:

口 -> 囗 出现 3 次 贴 -> 貼 是 -> 罡 / 杲 五 -> 岳 三 -> 十 八 -> 烈 5 -> 巧 28.9 -> 28、9

一个是「多切了一块」,一个是「把字认成别的字」。

这两种错,校对的时候查法不一样。多的字要通读,认错的字要盯偏旁相似的字。

桌面日历上的 18 和星期缩写,又小又挤,属于最容易认错的那类字
桌面日历上的 18 和星期缩写,又小又挤,属于最容易认错的那类字

六、数字最危险

这一项我觉得最该说。

32 张图里,数字串跟真值对不上的有 12 张。

RapidOCR 28.9 / 31.5 -> 2893315 多一个 3,出现 4 次 RapidOCR 28.9 / 31.5 -> 315289 顺序颠倒 RapidOCR 10 / 18 -> 10187 两个日期粘一起 Windows 28.9 / 31.5 -> 2831 小数点没了,31.5 也没了 Windows 28.9 -> 28四 小数点认成汉字 Windows 31.5 -> 31巧 5 认成汉字 Windows 48 -> 空 整个数字消失 Windows 10 / 18 -> 711018 多一个 1

价格、日期、电话、编号,全是这种死法。

文字错一个字,读者能猜。数字错一位,意思就变了。31.5 变 315,是十倍的差。

所以我现在的做法是:金额和日期一律人工核一遍,不管 OCR 报得多自信。

七、速度差 140 倍

同一张 812×104 的图,预热后各跑 10 次,取中位数:

RapidOCR 2237 ms Windows OCR 16 ms

140 倍。

原因在这台机器上:2 个逻辑核,没有独显,onnxruntime 只有 CPUExecutionProvider 可用。

RapidOCR 是把模型放在 CPU 上跑,onnxruntime 没别的提供者可用。Windows 那个是系统自带的接口,内部怎么实现我没查。

所以这 140 倍里有多少是算法差距,有多少是我这台 2 核机器的差距,我分不开。

真放服务器上,RapidOCR 不会这么慢。具体多快我没在别的机器上测过,不敢写数。

一辆蓝色嘟嘟车的车头,车牌上是泰文
一辆蓝色嘟嘟车的车头,车牌上是泰文

八、要是你只想要一个结论

按图选:

小字截图,代码截图,网页截屏。用 RapidOCR。

手机拍的纸,可能有点歪。用 Windows 那个,行序更靠得住。

要处理上千张,又不想装模型。Windows 自带那个够了。

有 GPU,或者图里是表格、竖排、手写。这两个我都没测到那儿,别拿这篇当依据。

我没验证的地方

图是我自己渲染的。

不是扫描件,不是手机拍的照片,没有折痕、没有阴影、没有透视变形。真实照片的难度比这高。所以上面这些百分比,只能横向比两个引擎,不能当「实际准确率」用。

手写、竖排、印章、表格,全没测。

这四类恰恰是现实里最容易崩的。我知道它们难,但我没有数据,不编。

Windows 语言包只用了 zh-Hans-CN。

换语言包、换系统版本,结果会变。我这台只有这一个中文包。

那张嘟嘟车照片没算进样本。

车牌上是泰文。两个引擎都不是泰文识别器,读不出来是正常的,没有比较意义。我把它放在这里只是说明:别拿不认识的语种去测。

耗时只在这一台机器上测过。

2 核,无 GPU。换个环境,那个 140 倍会缩。


一句话

OCR 报出来的是一段文本,不是一个承诺。

它不会告诉你哪个字它没把握。所以数字和编号,永远自己看一眼。

你手上是哪种图多,小字截图还是拍歪的纸?我可以按那个条件再补一组数据。