今天来跟大伙聊下图片 OCR 识别,提到这个,一般可能都会想到著名的 tesseract-ocr。
在 Node.js 程序中处理如验证码识别一类的文本或物体识别时,需要以 Node.js API 的方式调用。一般来说有三种可实现该需求的方式:包装本地安装的 OCR 应用程序(如 tesseract-ocr)以提供 Node.js 调用接口、通过 http 请求方式调用第三方在线服务以及使用支持 node.js 第三方依赖库存(比如说 tesseract.js)。
这种方案要求首先在本地机器安装并配置要包装的 OCR 应用。然后使用 node.js child_process 模块的 exec、spawn 等方法调用 OCR 应用,并将执行后的结果处理后返回。
npm 能找到的大多为基于 tesseract-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 本质上也是基于 tesseract-ocr 的封装,但其不同的是它借助 emscripten 将 C++ 开发的 tesseract-ocr 编译为 WebAssembly 实现能力支持,现代浏览器均支持 WebAssembly ,故其也可直接在浏览器中应用。
以下对使用 tesseract.js 实现 OCR 文本识别作简要介绍。
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
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 以及其训练数据相关工具。
具体的方法可参考官方相关仓库和文档:
另外也有一些可参考的教程:
以验证码为例,下面为获取一定数量的验证码作为训练集。由于训练的图片只能为 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 => {
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:
(如果你们有什么想法或者有什么错误的地方,可以在评论区留言)
留言与评论(共有 0 条评论) “” |