目前最流行的开源OCR软件是tesseract,是一个google支持的开源ocr项目tesseract,现已有大神用JavaScript将tesseract集成tesseractjs的npm包,那我们这里直接用nodejs+tesseractjs来实现ocr功能。
安装 npm i tesseract.js
tesseract.js使用的语言包下载地址各国语言包,按需下载即可,也支持自己训练数据模型。
程序入口,引入需要用的包
const express = require('express');
const tesseract = require('tesseract.js');
const images = require('images')
const app = express();
const bodyParser = require("body-parser");
const sharp = require('sharp');
const Jimp = require('jimp');
先写一个接口,接受图片base64
app.post('/ocr', async(req, res) => {
var buff = new Buffer.from(req.body.ImageBase64, 'base64');
let sharpImg = buff
images(buff).size(90).save('./test.png')
})
保存上传的图片,也可直接使用buff进行识别
使用tesseract直接识别
tesseract.recognize('./test.png', 'eng').then(function(p) {
console.log(p.data.text);
})
由于该验证码有黑色边框,导致识别出空字符串,我们先将图像做边框裁剪处理
// 调用sharp库进行切割和保存
const { width, height } = await sharp(sharpImg).metadata();
const top = 2;
const bottom = 2;
const left = 2;
const right = 2;
const croppedWidth = width - left - right;
const croppedHeight = height - top - bottom;
if (croppedWidth <= 0 || croppedHeight <= 0) {
throw new Error('切割后的图像尺寸无效!');
}
await sharp(sharpImg)
.extract({
top: top,
left: left,
width: croppedWidth,
height: croppedHeight
})
.toBuffer((err, buffer) => {
if (err) {
console.error(err);
return;
}
// 在这里可以使用保存的 Buffer 对象进行后续操作
// 例如,将其发送到客户端或保存到文件等
sharpImg = buffer
});
sharpImg为图片路径或buff等格式,这样我们获取到去除黑色边框的切割图片
识别结果还是为空字符串,由于噪点密集,造成识别率很低,接下来我们将图片转换为灰度图像,并且进行降噪和二值化处理。
降噪处理是图像处理中的一种基本操作,主要目的是消除图像中的噪声(包括因传感器、照明等原因引入的噪声)或细节,以便更好地突出图像中的关键特征。常见的降噪算法包括均值滤波、中值滤波、高斯滤波等。例如,使用中值滤波器可以将每个像素的值替换为其邻域值的中值,从而滤除噪声。
二值化处理也是一种常用的图像处理操作,它将一张灰度图像转换为一个二值图像,即只有黑色和白色两种颜色的图像。在图像识别、字符识别等领域,二值化处理常用于分离文本、检测边缘、识别目标等应用场景中。常见的二值化算法包括全局阈值法、局部阈值法、自适应阈值等。例如,在全局阈值法中,通过将图像中所有像素的灰度值与一个预先定义的阈值进行比较,将大于阈值的像素设为白色,小于等于阈值的像素设为黑色,从而实现二值化处理。
// 加载图像
await Jimp.read(sharpImg)
.then(image => {
// 转换为灰度图像
image.greyscale();
// 二值化处理
image.scan(0, 0, image.bitmap.width, image.bitmap.height, (x, y, idx) => {
const red = image.bitmap.data[idx + 0];
const green = image.bitmap.data[idx + 1];
const blue = image.bitmap.data[idx + 2];
// const avg = (red + green + blue) / 3;
// const threshold = 158; // 阈值
if (red < 30 && green < 30 && blue < 30) {
image.bitmap.data[idx + 0] = 255;
image.bitmap.data[idx + 1] = 255;
image.bitmap.data[idx + 2] = 255;
}
});
// 保存处理后的图像
image.write('./deal.png');
return image.getBufferAsync(Jimp.MIME_PNG);
}).then(buffer => {
// 在这里可以使用保存的 Buffer 对象进行后续操作
// 例如,将其发送到客户端或保存到文件等
sharpImg = buffer
})
.catch(err => {
console.error(err);
});
这样我们的图像过滤了多余影响:
进行ocr识别:
识别成功率跟图像复杂度有关系,你也可以进行模型训练达到提高识别成功率的效果。
最终代码
app.post('/ocr', async(req, res) => {
var buff = new Buffer.from(req.body.ImageBase64, 'base64');
let sharpImg = buff
// 调用函数进行切割和保存
const { width, height } = await sharp(sharpImg).metadata();
const top = 2;
const bottom = 2;
const left = 2;
const right = 2;
const croppedWidth = width - left - right;
const croppedHeight = height - top - bottom;
if (croppedWidth <= 0 || croppedHeight <= 0) {
throw new Error('切割后的图像尺寸无效!');
}
await sharp(sharpImg)
.extract({
top: top,
left: left,
width: croppedWidth,
height: croppedHeight
})
.toBuffer((err, buffer) => {
if (err) {
console.error(err);
return;
}
// 在这里可以使用保存的 Buffer 对象进行后续操作
// 例如,将其发送到客户端或保存到文件等
sharpImg = buffer
});
// 加载图像
await Jimp.read(sharpImg)
.then(image => {
// 转换为灰度图像
image.greyscale();
// 二值化处理
image.scan(0, 0, image.bitmap.width, image.bitmap.height, (x, y, idx) => {
const red = image.bitmap.data[idx + 0];
const green = image.bitmap.data[idx + 1];
const blue = image.bitmap.data[idx + 2];
if (red < 30 && green < 30 && blue < 30) {
image.bitmap.data[idx + 0] = 255;
image.bitmap.data[idx + 1] = 255;
image.bitmap.data[idx + 2] = 255;
}
});
// 保存处理后的图像
image.write('./ecardDeal.png');
return image.getBufferAsync(Jimp.MIME_PNG);
}).then(buffer => {
// 在这里可以使用保存的 Buffer 对象进行后续操作
// 例如,将其发送到客户端或保存到文件等
sharpImg = buffer
})
.catch(err => {
console.error(err);
});
tesseract.recognize(sharpImg, 'glg').then(function(p) {
console.log('progress', p.data.text);
}).then(function(result) {
console.log('err', result);
});
})
码字不易,欢迎体验智能小工具