提到图片 OCR 识别,一般可能都会想到著名的 tesseract-ocr。
在 Node.js 程序中处理如验证码识别一类的文本或物体识别时,需要以 Node.js API 的方式调用。一般来说有三种可实现该需求的方式:包装本地安装的 OCR 应用程序(如 tesseract-ocr)以提供 Node.js 调用接口、通过 http 请求方式调用第三方在线服务以及使用支持 node.js 的第三方依赖库(如 tesseract.js)。
包装本地 OCR 应用程序 API
这种方案要求首先在本地机器安装并配置要包装的 OCR 应用。然后使用 node.js child_process
模块的 exec、spawn
等方法调用 OCR 应用,并将执行后的结果处理后返回。
npm 上能找到的大多为基于 tesseract-ocr
实现的包装,主要区别在于包装后的 API 易用性。相关实现参考:
- https://github.com/tesseract-ocr/tesseract
- https://github.com/nicolaspearson/node.ts.ocr
使用第三方在线服务 API
BAT 都提供有相关的在线服务 API,这些在线 API 的用法一般也都比较简单,少量的调用基本都是免费的。另外一些在线打码平台也会提供相关收费 API 服务。下面以百度智能云为例作简单示例介绍。
使用百度账号登陆百度 AI 智能云平台,并新建一个应用,然后进入应用管理可得到 APPId、key、和 secret。
百度智能云控制台:https://console.bce.baidu.com/ai/#/ai/ocr/overview/index
百度智能云平台提供了相当多的人工智能相关的 API 开放服务。以下为 node.js 调用百度智能云 OCR API 实现图片文本识别的一个示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // 需先安装其 SDK 包: npm -i badidu-aip-sdk // const AipOcrClient = require('baidu-aip-sdk').ocr; const AipOcrClient = require( 'baidu-aip-sdk/AipOcr' ); const fs = require( 'fs' ); const APP_ID = '14406xxx' ; const API_KEY = 'Fz7XXXXXXXXXXX' ; const SECRET_KEY = 'XEXXXXXXXXXXXXXX' ; const client = new AipOcrClient(APP_ID, API_KEY, SECRET_KEY); const ocrTextTest = async () => { const options = { detect_direction: true }; // 识别本地图片 const image = fs.readFileSync( './donate_wx.png' ).toString( 'base64' ); let result = client.generalBasic(image, options); console.log(result.words_result); // 识别在线图片 const result = await client.generalBasicUrl( 'https://lzw.me/wp-content/uploads/2017/02/donate_wx.png' ); console.log(result.words_result); } ocrTextTest(); |
使用 tesseract.js
库实现 OCR 识别
tesseract.js 本质上也是基于 tesseract-ocr
的封装,但其不同的是它借助 emscripten
将 C++ 开发的 tesseract-ocr
编译为 WebAssembly
实现能力支持,现代浏览器均支持 WebAssembly
,故其也可直接在浏览器中应用。
以下对使用 tesseract.js
实现 OCR 文本识别作简要介绍。
安装 tesseract.js
依赖
1 2 3 | npm i tesseract.js # or yarn add tesseract.js |
下载训练数据
tesseract.js
默认从其网站下载训练数据,但由于训练数据包比较大,可能需要比较久的时间。我们可以先使用迅雷等工具将其下载下来,然后通过 langPath
参数指定训练数据的位置。
下载地址示例: https://tessdata.projectnaptha.com/4.0.0_fast/chi_sim.traineddata.gz
下载其他语言类型的训练数据,只需将示例地址中的 chi_sim
改为要下载的语言标识即可。
当然你也可以从其默认训练数据的仓库下载(可能会因 git 拉取太久而失败),所有默认支持的的语言也都可以从这里知晓。
默认训练数据仓库地址为:https://github.com/naptha/tessdata
基于 tesseract.js
的图片文本识别示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | const Tesseract = require( 'tesseract.js' ); const path = require( 'path' ); const worker = Tesseract.createWorker({ logger: m => console.log(m), errorHandler: err => console.log( '[error:]' , err), // 使用离线训练数据 langPath: path.resolve(__dirname, './tessdata/4.0.0_best' ), }); const ocrTest = async () => { await worker.load(); await worker.loadLanguage( 'chi_sim' ); await worker.initialize( 'chi_sim' ); await worker.setParameters({ // 验证码只为数字的情况下,设定白名单 // tessedit_char_whitelist: '0123456789', tessedit_pageseg_mode: tessedit_pageseg_mode: Tesseract.PSM.AUTO, }); // const image = require('fs').readFileSync('./donate_wx.png'); const { data: { text } } = await worker.recognize(image); console.log(text); await worker.terminate(); }); ocrTest(); |
以上示例为对文本对识别。
自行训练自定义数据
默认支持的训练数据相对比较弱,对于文字比较清晰的图片来说一般没有问题,但对于存在干扰的验证码这种需求来说,则需要通过自行训练来提升准确率。
tesseract.js
使用的训练数据只是将 tesseract-ocr
gzip 压缩了一下而已,训练自定义的数据需要安装 tesseract-ocr
以及其训练数据相关工具。
具体的方法可参考官方相关仓库和文档:
- 安装 tesseract-OCR:https://github.com/tesseract-ocr/tessdoc/blob/master/Installation.md
- https://github.com/tesseract-ocr/tesstrain
- https://github.com/tesseract-ocr/tessdoc/blob/master/Compiling.md
另外也有一些可参考的教程:
- https://zhuanlan.zhihu.com/p/103714876
- https://github.com/kekxv/TesseractTrain
- https://www.bbsmax.com/A/6pdDb7pDJw/
- https://www.bbsmax.com/A/8Bz8KNOkdx/
- https://www.ershicimi.com/p/9bf5ec129082ac6800b1cb6f56c6f71c
- https://blog.csdn.net/sylsjane/article/details/83751297
- https://blog.csdn.net/holmofy/article/details/80867243
- https://blog.csdn.net/makesibushuohua/article/details/52058310
获取用于训练的图片
以验证码为例,下面为获取一定数量的验证码作为训练集。由于训练的图片只能为 png 格式,使用了 sharp 库将下载得到的图片转换为 png 格式。sharp 安装过程中需要从 GitHub 仓库下载二进制资源,可能会因为无法下载而安装失败,我们执行如下命令设置从淘宝镜像下载相关资源:
1 2 |
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | import fs from 'fs' ; import http from 'http' ; import https from 'https' ; import sharp from 'sharp' ; const downloadImage = (imageUrl: string): Promise<buffer> => { return new Promise((resolve, reject) => { (imageUrl.startsWith( 'https' ) ? https : http).get(imageUrl, (res) => { const chunks: Buffer[] = []; res.on( 'data' , (chunk) => chunks.push(chunk)); res.on( 'end' , (error: Error) => { if (error) return reject(error); const size = chunks.map(d => d.length).reduce((val, total) => val + total, 0); resolve(Buffer.concat(chunks, size)); }); }); }); }; const getCodeImgUrl = () => `https: //lzw.me/getcaptcha?theme=light&_pc=${Date.now()}`; export const saveImages = async (total = 100, nameBase = 10000, baseDir = './images/captcha/' ) => { if (!fs.existsSync(baseDir)) fs.mkdirSync(baseDir, { recursive: true }); console.log( '等待下载的图片数量:' , total); await downloadImage(getCodeImgUrl()).then(buf => { return sharp(buf).png().toFile(path.resolve(baseDir, `${nameBase++}.png`)); }); await new Promise(rs => setTimeout(() => rs( null ), Math.ceil(Math.random() * 700 + 300))); if (--total) await saveImages(total, nameBase, baseDir); }; saveImages(10, 100, './images/captcha_1/' ); |
然后可以人肉识别,将验证码图片重命名为其对应的验证码值,以便用于后续的训练,有重名的可以加上后缀如 -1
。
除了 之外,还有 opencv:
- https://www.npmjs.com/package/opencv
- https://www.npmjs.com/package/opencv-wasm
相关参考
- https://github.com/tesseract-ocr/tesseract
- https://github.com/naptha/tesseract.js/
- https://github.com/emscripten-core/emscripten
- https://github.com/UB-Mannheim/tesseract/wiki
- https://www.npmjs.com/package/captcha-cv-ocr