nodejs的一种图像识别方法
# nodejs图片验证码识别
由于微信小程序云开发使用npm中的gm图像处理工具有些困难,因为gm需要在linux环境下额外安装native的包。所以我使用了nodejs canvas来处理图像然后放入tesseractjs中进行识别。场景是用于带有图片验证码登录的爬虫。
nodejs识别图像验证码主要分为3步
- 图片灰度化
- 灰度图片二值化
- nodejs保存图片数据为图片文件
- 用ocr工具识别图片
# 图片灰度化
灰度化,在 RGB 模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。图片灰度化的细节不会详细讲,可以自行百度。
在图片灰度化之前要安装canvas,引入canvas用于处理图像文件,由于二维码图片尺寸固定,本例中的二维码图片是92*34,在创建canvas 时就固定了长和宽。
const { createCanvas, loadImage} = require('canvas');
const canvas = createCanvas(92, 34);
const ctx = canvas.getContext('2d');
loadImage('./1.jpg').then(image => {
ctx.drawImage(image, 0, 0, 92, 34)
ProcessToGrayImage(ctx);
//灰度化
OTSUAlgorithm(120);
//二值化
fs.writeFileSync('./2.jpg',dataURLtoFile(canvas.toDataURL()),{flag:'w'})
})
2
3
4
5
6
7
8
9
10
11
# 灰度化函数
function ProcessToGrayImage(ctx) {
//取得图像数据 //
var imgData = ctx.getImageData(10, 10, 50, 50);
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
//这个循环是取得图像的每一个点,在计算灰度后将灰度设置给原图像
for (var x = 0; x < canvasData.width; x++) {
//alert("x="+x);
for (var y = 0; y < canvasData.height; y++) {
//alert("y="+y);
// Index of the pixel in the array
var idx = (x + y * canvas.width) * 4;
// The RGB values
var r = canvasData.data[idx + 0]; var g = canvasData.data[idx + 1]; var b = canvasData.data[idx + 2];
//更新图像数据
var gray = CalculateGrayValue(r, g, b);
canvasData.data[idx + 0] = gray;
canvasData.data[idx + 1] = gray;
canvasData.data[idx + 2] = gray; }
}
ctx.putImageData(canvasData, 0, 0);}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# nodejs保存图片数据为图片文件
这里的dataURLtoFile是将图片base64数据转化为二进制图片数据方便写入文件中。参考了思否qylcx7758
大佬的回答。
const atob = require('atob');
function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length,
u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return u8arr;
}
2
3
4
5
6
7
8
9
10
11
atob()
函数能够解码通过base-64编码的字符串数据。相反地,btoa()
函数能够从二进制数据“字符串”创建一个base-64编码的ASCII字符串。由于nodejs中没有atob(浏览器有),所以要从npm中下载才能够使用atob的功能。
# 图片二值化
图像二值化( Image Binarization)就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程。因为ocr功能往往会被噪点所影响,所以图片二值化设置合理的阈值可以取消掉图片中的浅色小点,提高ocr识别精度,本例中的阈值为120。
# 二值化函数
二值化的阈值可以用概率计算出一个合适的值,但在本例中不尽人意,在本文中使用手动设置阈值为120,比较方便快速的过滤了图片中的灰色小点。
function OTSUAlgorithm(threshold) {
var imageInfo = GetGrayImageInfo(ctx);
if (imageInfo == null) {
console.warn("图像还没有转化为灰度图像!");
return;
}
//获取图像信息
var canvasData = imageInfo[0];
//下面执行二值化过程
for (i = 0; i < canvasData.width; i++) {
for (j = 0; j < canvasData.height; j++) {
//取得每一点的位置
var ids = (i + j * canvasData.width) * 4;
//取得像素的R分量的值
var r = canvasData.data[ids];
//与阀值进行比较,如果小于阀值,那么将改点置为0,否则置为255
var gray = r > threshold ? 255 : 0;
canvasData.data[ids + 0] = gray;
canvasData.data[ids + 1] = gray;
canvasData.data[ids + 2] = gray;
}
}
//显示二值化图像 //
var newImage = document.getElementById('myCanvas').getContext('2d');
ctx.putImageData(canvasData, 0, 0);}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 完整的生成二值化图像的代码
const fs = require('fs');
const atob = require('atob');
const { createCanvas, loadImage} = require('canvas')
const canvas = createCanvas(92, 34);
const ctx = canvas.getContext('2d')
console.log(ctx)
function ProcessToGrayImage(ctx) {
//取得图像数据 //
var imgData = ctx.getImageData(10, 10, 50, 50);
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
//这个循环是取得图像的每一个点,在计算灰度后将灰度设置给原图像
for (var x = 0; x < canvasData.width; x++) {
//alert("x="+x);
for (var y = 0; y < canvasData.height; y++) {
//alert("y="+y); // Index of the pixel in the array
var idx = (x + y * canvas.width) * 4;
// The RGB values
var r = canvasData.data[idx + 0];
var g = canvasData.data[idx + 1];
var b = canvasData.data[idx + 2];
//更新图像数据
var gray = CalculateGrayValue(r, g, b);
canvasData.data[idx + 0] = gray;
canvasData.data[idx + 1] = gray;
canvasData.data[idx + 2] = gray;
}
}
ctx.putImageData(canvasData, 0, 0);}
//一维OTSU图像处理算法
function OTSUAlgorithm(threshold) {
var imageInfo = GetGrayImageInfo(ctx);
if (imageInfo == null) {
console.warn("图像还没有转化为灰度图像!");
return;
}
//获取图像信息
var canvasData = imageInfo[0];
//下面执行二值化过程
for (i = 0; i < canvasData.width; i++) {
for (j = 0; j < canvasData.height; j++) {
//取得每一点的位置
var ids = (i + j * canvasData.width) * 4;
//取得像素的R分量的值
var r = canvasData.data[ids];
//与阀值进行比较,如果小于阀值,那么将改点置为0,否则置为255
var gray = r > threshold ? 255 : 0;
canvasData.data[ids + 0] = gray;
canvasData.data[ids + 1] = gray;
canvasData.data[ids + 2] = gray;
}
}
//显示二值化图像 //
var newImage = document.getElementById('myCanvas').getContext('2d'); ctx.putImageData(canvasData, 0, 0);}
//获取图像的灰度图像的信息
function GetGrayImageInfo(ctx) {
//
var canvas = document.getElementById('myCanvas');
//
var ctx = canvas.getContext('2d');
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
if (canvasData.data.length == 0) { return null; }
return [canvasData, ctx];}
//计算图像的灰度值,公式为:Gray = R*0.299 + G*0.587 + B*0.114function CalculateGrayValue(rValue, gValue, bValue) { return parseInt(rValue * 0.299 + gValue * 0.587 + bValue * 0.114);}
function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length,
u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return u8arr;
}
loadImage('./1.jpg').then(image => {
ctx.drawImage(image, 0, 0, 92, 34)
ProcessToGrayImage(ctx);
OTSUAlgorithm(120);
fs.writeFileSync('./2.jpg',dataURLtoFile(canvas.toDataURL()),{flag:'w'})
console.log('<img src="' + canvas.toDataURL() + '" />')
}
)
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# 用tesseract.js识别二值化后的图像
Tesseract (/'tesərækt/) 这个词的意思是”超立方体”,指的是几何学里的四维标准方体,又称”正八胞体”,是一款被广泛使用的开源 OCR 工具。 Tesseract 已经有30 年历史,开始它是惠普实验室于1985年开始研发的一款专利软件,到1995年一件成为OCR业界内最准确的识别引擎之一。
代码不多,从官方实例上面拷贝下来的
const { createWorker } = require('tesseract.js');
const worker = createWorker({ logger: m => {}});
(async () => {
await worker.load();
await worker.loadLanguage('eng');
await worker.initialize('eng');
const { data: { text } } = await worker.recognize('./2.jpg');
console.log(text);
await worker.terminate();})();
2
3
4
5
6
7
8
9