基于 opencv4nodejs 实现 OCR 验证码识别搭建私有 OCR 服务

目录
[隐藏]

1 @u4/opencv4nodejs 依赖安装及编译

opencv4nodejs 包提供了丰富de 接口,使得可以在 Node.js 下以更友好的方式使用 opencv4,但其原始仓库近两年不再更新。@u4/opencv4nodejs 是其 fork 版本,并保持持续更新中。

opencv4nodejs 由于涉及到 Native 编译,依赖安装及编译过程极其复杂。下面为在 windows 11 下编译安装 @u4/opencv4nodejs 的过程,仅供参考。

1.1 安装 @u4/opencv4nodejs 相关依赖

在项目目录下执行命令添加依赖。示例:

yarn add -D node-gyp
yarn add @u4/opencv4nodejs

然后下载并全局安装 opencv4。可从该页面下载:https://opencv.org/releases/

该页面上的相关下载地址实际上是 github 仓库上的 release 资源。

也可以使用包管理安装。使用包管理器安装的命令参考:

# windows: scoop
scoop install opencv
# windows: chocolatey
choco install OpenCV -y -version 4.8.0

# macos: brew
brew install opencv

windows 下可以直接使用 IDM 等工具下载后解压安装。例如我这里解压在了 D:\opencv 目录(推荐解压安装至 c:\\tools\\opencv 目录,这是 build-opencv 使用的默认目录)。

1.2 使用 @u4/build-opencv 编译

以下为在 windows 11PowerSHell 中的编译方法参考。

先确保已安装了 MSBuild 工具链。如果安装了 Visual Studio 社区版并选择 C++ 编译下哦昂改名工具链即可。
也可以使用 npm 安装:npm i -g windows-build-tools

进入项目目录下,执行如下命令:

# 禁止从源码编译 opencv,使用全局安装的 opencv
$ENV:OPENCV4NODEJS_DISABLE_AUTOBUILD=1

# 指定全局安装的 opencv 路径。若安装在了 c:\\tools\\opencv 目录下(默认目录),则无需设置
$ENV:OPENCV_LIB_DIR="D:\opencv\build\x64\vc16\lib"
$ENV:OPENCV_BIN_DIR="D:\opencv\build\x64\vc16\bin"
$ENV:OPENCV_INCLUDE_DIR="D:\opencv\build\include"

# 执行自动编译
yarn build-opencv --nobuild auto
# 强制重新编译
# yarn build-opencv --nobuild rebuild

编译成功后,则会产出文件 node_modules/@u4/opencv4nodejs/build/Release/opencv4nodejs.node

可以用如下脚本测试其可用性:

const cv = require('@u4/opencv4nodejs');
// load image from file
const mat = cv.imread('./path/img.jpg');

// show image
cv.imshow('a window name', mat);

2 基于 @u4/opencv4nodejs 的验证码 OCR 识别

2.1 基于 @u4/opencv4nodejs 的滑块匹配验证码

滑块验证码识别是当前各大网站登录页面最为常见的一种。通过使用 @u4/opencv4nodejs 提供的 matchTemplate 方法,可以快速实现滑块验证码的识别。参考以下示例代码:

const cv = require('@u4/opencv4nodejs');
const fs = require('fs');

const sliderImage = fs.readFileSync('./slider.png');
const originalImage = fs.readFileSync('./original.png');

const sliderMat = cv.imdecode(sliderImage);
const originalMat = cv.imdecode(originalImage);
const matched = sliderMat.matchTemplate(originalMat, cv.TM_CCOEFF_NORMED);
const matchedPoints = matched.minMaxLoc();
console.log('x: ', matchedPoints.maxLoc.x, matchedPoints);

2.2 基于 @lzwme/captcha-cv-ocr 的验证码识别

captcha-cv-ocr 模块基于 @u4/opencv4nodejstesseract.js 封装实现了几种常见的验证码识别实现。我们可以安装并使用它首先简单的实现验证码识别能力。由于 captcha-cv-ocr 近两年未更新,@lzwme/captcha-cv-ocr 是本人基于 captcha-cv-ocr fork 并做了依赖升级、能力扩展等。

安装:

npm i @lzwme/captcha-ocr

2.2.1 基于 Node.js API 调用的使用

示例:

const { Cvocr, getCodesList } = require("captcha-cv-ocr");

// 获取支持的验证码识别类型列表
const codesList = getCodesList();
console.log('codes:', codesList);

async function cvocrTest() {
    // 获取支持的验证码识别类型列表
    const codesList = getCodesList();
    console.log('codes:', codesList);

    const mode = "simplest";
    const cvocr = new Cvocr(mode);
    await cvocr.init([{ num: 1 }]);
    // 支持文件地址、Base64、Buffer形式
    const imgBase64 = `data:image/jpg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAUADwDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtNVmn8t5fIluBGGdvJ/fSHHIAPc+n1rlLbXtbt7rTP7Z0+3t7K/m+zxRxEpNCxICeZng+/f1x0rtNVtzp1pJfSXCGytjJxKScBA+ePwNee6f4i0jXNat575w5MoisdOETfI3AEj4GC57DJC/XmprR1SZtGkmtrnZat9tjhA0tEkkJIaWSTMcWPXHOfwqHR9Se+tDDMY0nilaCRwuBlO4Oeh9xTNbns4I4PtUL/YLgMkkzE/uhjgYAJIJyMjFReEovNmvfsJl/soMotyrcA4+fAbnGf1zVKEeT3kc/JFS0Kut6/LpurafYWM0U0k08cc7MN4hDngdOCeT+HStTWtTn0vTJ9Qm82URkEeVIQCScdjxzjtXFarpeu6e2ntdnTLie41KJ/Oy5eSXnYH6fIB2GMV1/iFb5vC1wLeKQ37QBJVWMlOf9ZsyemN+O/TvXR7OklFIil70nchsdR1ODVbe28SW8Mj3isbdkWSQjYMkYZhwQeue3vXolheRfZI/OjnVscCO3ZVx2wPm7Y715d4ZXSx4m06XwqY/LWOVL2VhKAAQPLyWPGW/uc8HPFepxi/8ALX5rTp2Vm/XNVJpPT8jplBJks9nDLEsbplPND49y3P8AM1QubdZrTUFct/o8mxTnJOBkE56ntnriiiipsRLYkjto11Z7dgHhaIuUdVIzv+lTS6XafZf9SORvAPIQ7v4QeAPbp7UUU6YR2KOtWqWNq8sDPjjdG7blbkdc8/rU39l20l4kLhiFAIbPzdW70UVzvc0qbIL3TIreznZXkdM7vLkw46jjJG7H41NY2do9pEzWkGWUE/JRRRFe8zKXwo//2Q==`;
    // const imgFile = "simplest.jpg";
    // 支持文件地址、Base64、Buffer形式
    const ans = await cvocr.recognize(imgBase64);
    console.log("ans:", ans);
    process.exit(0);
}

cvocrTest();

2.2.2 基于 http API 的调用使用

@lzwme/captcha-cv-ocr 内置了一个简单的 server 能力,可以调用它提供本地 http 服务调用能力。基于 http server 的使用示例。

命令行下直接启动示例:

# 默认启动 3000 端口
node ./node_modules/@lzwme/captcha-cv-ocr/index.js

通过调用 createServer 方法启动 sever 示例:

const { createServer } = require('@lzwme/captcha-cv-ocr');

createServer({ port: 3000 });

然后即可通过 post 请求的方式使用。示例(基于 fetch API,可在 Node.js 环境或 chrome 控制台直接调用):

async function httpOcrTest() {
    const body = {
        mode: 'simplest',
        // 验证码图片
        base64: 'data:image/jpg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAUADwDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtNVmn8t5fIluBGGdvJ/fSHHIAPc+n1rlLbXtbt7rTP7Z0+3t7K/m+zxRxEpNCxICeZng+/f1x0rtNVtzp1pJfSXCGytjJxKScBA+ePwNee6f4i0jXNat575w5MoisdOETfI3AEj4GC57DJC/XmprR1SZtGkmtrnZat9tjhA0tEkkJIaWSTMcWPXHOfwqHR9Se+tDDMY0nilaCRwuBlO4Oeh9xTNbns4I4PtUL/YLgMkkzE/uhjgYAJIJyMjFReEovNmvfsJl/soMotyrcA4+fAbnGf1zVKEeT3kc/JFS0Kut6/LpurafYWM0U0k08cc7MN4hDngdOCeT+HStTWtTn0vTJ9Qm82URkEeVIQCScdjxzjtXFarpeu6e2ntdnTLie41KJ/Oy5eSXnYH6fIB2GMV1/iFb5vC1wLeKQ37QBJVWMlOf9ZsyemN+O/TvXR7OklFIil70nchsdR1ODVbe28SW8Mj3isbdkWSQjYMkYZhwQeue3vXolheRfZI/OjnVscCO3ZVx2wPm7Y715d4ZXSx4m06XwqY/LWOVL2VhKAAQPLyWPGW/uc8HPFepxi/8ALX5rTp2Vm/XNVJpPT8jplBJks9nDLEsbplPND49y3P8AM1QubdZrTUFct/o8mxTnJOBkE56ntnriiiipsRLYkjto11Z7dgHhaIuUdVIzv+lTS6XafZf9SORvAPIQ7v4QeAPbp7UUU6YR2KOtWqWNq8sDPjjdG7blbkdc8/rU39l20l4kLhiFAIbPzdW70UVzvc0qbIL3TIreznZXkdM7vLkw46jjJG7H41NY2do9pEzWkGWUE/JRRRFe8zKXwo//2Q==',
        // slide_match 模式的底图
        originalBase64: '',
    };
    const result = await fetch('http://localhost:3000/ocr', {
        method: 'post',
        body: JSON.stringify(body),
        headers: { 'Content-Type': 'application/json' }
    }).then(d => d.json());
    console.log(result);
}

3 扩展:基于 ocr_api_server 快速搭建基于 http API 的验证码识别服务

ddddocr 是一个基于 python 和 opencv 实现的 OCR 通用验证码识别 SDK,而 ocr_api_server | github 是基于 ddddocr 封装的 API 服务实现。

基于源码启动示例:

# 拉取代码
git clone --depth 1 git@gitee.com:fkgeek/ocr_api_server.git

# 安装依赖
pip install -r requirements.txt -i https://pypi.douban.com/simple

# 运行  可选参数如下
# --port 9898 指定端口,默认为9898
# --ocr 开启ocr模块 默认开启
# --old 只有ocr模块开启的情况下生效 默认不开启
# --det 开启目标检测模式

# 同时开启ocr模块以及目标检测模块
python ocr_server.py --port 9898 --ocr --det

基于源码的方式可能会因为 python 环境等因素出现各种问题而失败。基于 docker 的方式可以快速启动一个本地服务。docker hub 上有许多 ocr_api_server 的镜像,可以搜索并选择其一安装启动,基本上只需映射 9898 端口出来即可。

API 调用测试示例:

await fetch('http://localhost:9898/ocr/b64/json', {
    method: 'post',
    mode: "cors", // no-cors, *cors, same-origin
    cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
    credentials: "omit", // include, *same-origin, omit
    body: `/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAUADwDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtNVmn8t5fIluBGGdvJ/fSHHIAPc+n1rlLbXtbt7rTP7Z0+3t7K/m+zxRxEpNCxICeZng+/f1x0rtNVtzp1pJfSXCGytjJxKScBA+ePwNee6f4i0jXNat575w5MoisdOETfI3AEj4GC57DJC/XmprR1SZtGkmtrnZat9tjhA0tEkkJIaWSTMcWPXHOfwqHR9Se+tDDMY0nilaCRwuBlO4Oeh9xTNbns4I4PtUL/YLgMkkzE/uhjgYAJIJyMjFReEovNmvfsJl/soMotyrcA4+fAbnGf1zVKEeT3kc/JFS0Kut6/LpurafYWM0U0k08cc7MN4hDngdOCeT+HStTWtTn0vTJ9Qm82URkEeVIQCScdjxzjtXFarpeu6e2ntdnTLie41KJ/Oy5eSXnYH6fIB2GMV1/iFb5vC1wLeKQ37QBJVWMlOf9ZsyemN+O/TvXR7OklFIil70nchsdR1ODVbe28SW8Mj3isbdkWSQjYMkYZhwQeue3vXolheRfZI/OjnVscCO3ZVx2wPm7Y715d4ZXSx4m06XwqY/LWOVL2VhKAAQPLyWPGW/uc8HPFepxi/8ALX5rTp2Vm/XNVJpPT8jplBJks9nDLEsbplPND49y3P8AM1QubdZrTUFct/o8mxTnJOBkE56ntnriiiipsRLYkjto11Z7dgHhaIuUdVIzv+lTS6XafZf9SORvAPIQ7v4QeAPbp7UUU6YR2KOtWqWNq8sDPjjdG7blbkdc8/rU39l20l4kLhiFAIbPzdW70UVzvc0qbIL3TIreznZXkdM7vLkw46jjJG7H41NY2do9pEzWkGWUE/JRRRFe8zKXwo//2Q==`,
    headers: {
        token: 'e939b7e5-5dbe-41c2-81bb-393a0de75425'
    }
}).then(d => d.json())

若希望允许在浏览器中跨域调用,则可以增加一个前置 nginx,配置 htttps 证书和 CORS header 头。nginx cors 配置参考:

# * 星号代表任意跨源请求都支持
# add_header Access-Control-Allow-Origin '*';
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials "true";
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers  'Content-Type,token,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,XRequested-With';

if ($request_method = 'OPTIONS') {
        return 200;
}

4 总结与参考

本文主要介绍了 @u4/opencv4nodejs 在 windows 下的安装与编译方法,并介绍了基于 @u4/opencv4nodejstesseract.js 封装实现验证码识别的开源项目 captcha-cv-ocr。并继续介绍了本人基于captcha-cv-ocr 扩展实现的 @lzwme/captcha-cv-ocr 包,通过使用 @lzwme/captcha-cv-ocr 可以在 Node.js 应用中快速的实现验证码识别能力,同时也可以简单快速的启动一个 http server 以提供 http 请求方式的验证码识别服务。

其它验证码识别类的相关仓库参考:

点赞 (0)

发表回复

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

Captcha Code