Node.js 应用中实现 OCR 验证码识别

目录
[隐藏]

提到图片 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 实现图片文本识别的一个示例:

// 需先安装其 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 依赖

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 的图片文本识别示例

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 image = 'https://lzw.me/wp-content/uploads/2017/02/donate_wx.png';
    const { data: { text } } = await worker.recognize(image);
    console.log(text);
    await worker.terminate();
});

ocrTest();

以上示例为对文本对识别。

自行训练自定义数据

默认支持的训练数据相对比较弱,对于文字比较清晰的图片来说一般没有问题,但对于存在干扰的验证码这种需求来说,则需要通过自行训练来提升准确率。

tesseract.js 使用的训练数据只是将 tesseract-ocr gzip 压缩了一下而已,训练自定义的数据需要安装 tesseract-ocr 以及其训练数据相关工具。

具体的方法可参考官方相关仓库和文档:

另外也有一些可参考的教程:

  • 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 仓库下载二进制资源,可能会因为无法下载而安装失败,我们执行如下命令设置从淘宝镜像下载相关资源:

npm config set sharp_binary_host "https://npm.taobao.org/mirrors/sharp"
npm config set sharp_libvips_binary_host "https://npm.taobao.org/mirrors/sharp-libvips"

代码示例:

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
点赞 (1)

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

Captcha Code