由于微信小程序云开发使用npm中的gm图像处理工具有些困难,因为gm需要在linux环境下额外安装的包。所以我使用了 来处理图像然后放入中进行识别。场景是用于带有图片验证码登录的爬虫。
识别图像验证码主要分为3部。
图片灰度化
灰度图片二值化
保存图片数据为图片文件
用ocr工具识别图片
图片灰度化
灰度化,在 RGB 模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。图片灰度化的细节不会详细讲,可以自行百度。
在图片灰度化之前要安装,引入用于处理图像文件,由于二维码图片尺寸固定,本例中的二维码图片是92*34,在创建 时就固定了长和宽。
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'})})
灰度化函数
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);}
保存图片数据为图片文件
这里的是将图片数据转化为二进制图片数据方便写入文件中。参考了思否大佬的回答。
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;}
atob() 函数能够解码通过base-64编码的字符串数据。相反地,btoa() 函数能够从二进制数据“字符串”创建一个base-64编码的ASCII字符串。由于中没有atob(浏览器有),所以要从npm中下载才能够使用atob的功能。
图片二值化
图像二值化( Image )就是将图像上的像素点的灰度值设置为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);}
完整的生成二值化图像的代码
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(' + '" />')})
用.js识别二值化后的图像
(/’tesərækt/) 这个词的意思是”超立方体”,指的是几何学里的四维标准方体,又称”正八胞体”,是一款被广泛使用的开源 OCR 工具。 已经有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();})();
原先图片和生成图片的效果图
参考文章
…
…
/q/…
希望js变得越来越好,也越来越方便。