lmk123 / blog

个人技术博客,博文写在 Issues 里。
https://github.com/lmk123/blog/issues
623 stars 35 forks source link

Tesseract.js 在划词翻译里的简单应用 #88

Open lmk123 opened 3 years ago

lmk123 commented 3 years ago

最近上线了截图翻译的功能,大致流程就是在前端页面截图后,调用某云的 OCR 接口将截图转成文字然后翻译。但是,使用某云的接口需要用户自行申请,这对普通用户来说很不方便,于是就想找找看有没有能直接在浏览器里使用的文字识别工具,然后就发现了 Tesseract.js

我本来以为,有了它就可以代替 OCR 接口了,但使用之后发现是我想多了。

以下使用感受来自一台 8 核 3.6 GHz、16 GB 内存的 Windows 电脑。

识别速度慢

我使用了 8 个 worker、每个 worker 都只加载了英语的数据包,识别一张 300 x 100 像素的截图需要 4 秒左右。而且我发现,用 1 个 worker 和用 8 个 worker 在识别时间上并没有太大差距,都是 4 秒左右,但如果多加载一个简体中文的数据包,识别时间就会翻倍。

我猜测这是因为截图不够大,所以体现不出多个 worker 的优势,而语种检测的过程似乎无法用 worker 分担,只要加载了两个语种数据包,无论是 1 个 worker 还是 8 个 worker 都是 8 秒左右。

相比之下,OCR 接口一般 2 秒内就可以返回结果。

系统资源占用过大

我用 Chrome 的任务管理器观察划词翻译的内存占用,在没有使用 Tesseract.js 之前,划词翻译的常驻内存大约是 77MB,然后:

  1. 在使用 1 个 worker、一个英语语种包进行图片识别的过程中,内存占用峰值达到了 492MB,识别结束后的常驻内存也有 401MB;
  2. 如果改为 8 个 worker,这两个数据分别是 3,083MB 和 2,769MB;
  3. 如果再加一个简体中文的语种包,这两个数据是 5,079MB 和 4,037MB;
  4. 最后我尝试把 worker 加到 16 个——Chrome 提示我划词翻译崩溃了。

相比之下,使用 OCR 接口几乎不消耗系统资源——毕竟只是发送了一个 HTTP 请求。

识别不准

我使用了英语语种包和简体中文语种包进行了测试,发现英语识别的准确度还比较好,但是中文识别出来的内容几乎不能用。相比之下,OCR 接口对中文和英文的识别率都很高。

结论

虽然没有进行精确的测量,但根据上面的观察,我对划词翻译里的 Tesseract.js 做了一些限制。

Tesseract.js 还支持一些参数,也许调整这些参数会改善前面提到的一些弊端,等有空了再试吧,不过我倒是理解“人工智能调参师”的梗了 :joy:


我调好参数了 :joy:

解决识别准确率不高的问题

识别不准是因为默认使用的训练数据不是准确率最高的。tesseract-ocr 提供了三种训练数据,Tesseract.js 默认使用的训练数据是 tessdata,但准确率最高的是 tessdata_best,所以需要将 langPath 改为 'https://tessdata.projectnaptha.com/4.0.0_best',使用这个训练数据识别的中文就很准确了。

但是,准确率高意味着识别时间变长了。经过简单测试,图片中包含的文字越多,识别的时间越长。短一点的文本如 20 个汉字或 70 个英文字母以下可以在 2 秒内识别出来,平常常见的一个段落大概需要 6 秒,但我觉得也是可以接受的。

相关链接:

解决系统资源占用的问题

在前面的文章中,我对每一次截图都尝试用多个 worker 来处理,但我现在发现,一个图片只会被一个 worker 处理,增加多个 worker 只是白白的占用内存,所以在划词翻译的截图翻译场景中,每次截图只需要生成一个 worker 来处理就好。创建一个使用 tessdata_best 且只加载一个语种的 worker 大概需要 700 毫秒,大约占用 300MB 内存,这个资源占用还是可以接受的,但也不能常驻。为了尽可能的减少这 700 毫秒的创建时间,比较好的做法是创建 worker 之后先不要立刻销毁,如果用户一段时间内没有截图再销毁。

识别时间较长

这个问题没有比较好的办法了,目前能做的就是限制 worker 只加载一个语种,避免识别时间翻倍。可以在截完图之后显示一个语种选择下拉框,用于让用户自行指定语种。然后告知用户在截图里少选一些文字会识别得更快。