需求:公司做会员卡实体卡的项目,需要扫码绑定用户,制卡商给了一个pdf文件里面包含2000张会员卡要求确认印刷,需要扫描出二维码内容并确定
这个任务被安排到我身上(本人前端),领导让手动扫码,作为一个程序员怎么可能干这么蠢的事呢,想着写个脚本解决一下,以下为解决步骤:
有一个很方便的网站 iLovePDF | Online PDF tools for PDF lovers可以在线把pdf转为图片
这里我用node写了个脚本把图片平均分为五行五列,就实现了每个图片上有一个二维码
const fs=require('fs');
const sharp=require('sharp');
const filesArr=fs.readdirSync('./ilovepdf_pages-to-jpg');
for (let i=0; i<filesArr.length; i++) {
const fileName=filesArr[i];
const inputImagePath='./ilovepdf_pages-to-jpg/'+fileName;
// 设置输入图片路径和输出文件夹路径
const outputFolderPath='./output_images';
// 读取输入图片数据
const imageBuffer=fs.readFileSync(inputImagePath);
// 创建输出文件夹
if (!fs.existsSync(outputFolderPath)) {
fs.mkdirSync(outputFolderPath);
}
// 设置分割参数
const numRows=5; // 分割行数
const numCols=5; // 分割列数
const imgHandle=async () => {
const imageInfo=await sharp(imageBuffer).metadata();
const imageHeight=imageInfo.height;
const imageWidth=imageInfo.width;
const blockWidth=Math.floor(imageWidth/numCols);
const blockHeight=Math.floor(imageHeight/numRows);
// 分割图片
for (let row=0; row<numRows; row++) {
for (let col=0; col<numCols; col++) {
const x=col*blockWidth;
const y=row*blockHeight;
sharp(imageBuffer)
.extract({ left: x, top: y, width: blockWidth, height: blockHeight })
.toFile(`${outputFolderPath}/${i}_${row}_${col}.png`, (err) => {
if (err) {
console.error(`Error saving ${i}_${row}_${col}.png:`, err);
} else {
console.log(`Saved ${i}_${row}_${col}.png`);
}
});
}
}
}
imgHandle()
}
这里我又写了个脚本
const fs=require('fs');
const resultFilePath='./multi_qr_results.txt';
const failFilePath='./fail.txt';
const filesList=fs.readdirSync('./output_images')
let num=0
var jsqr=require('jsqr');
var Jimp=require('jimp');
filesList.forEach((item, index) => {
var buffer=fs.readFileSync('./output_images/'+item);
Jimp.read(buffer).then(function (blockimg) {
var width=blockimg.bitmap.width,
height=blockimg.bitmap.height,
imgData=blockimg.bitmap.data;
var code=jsqr(imgData, width, height,'invertFirst');
if (code) {
console.log(code.data);//内容
fs.appendFileSync(resultFilePath, `${item}: ${code.data},\n`);
// successObj.item = code.data
} else {
console.log('未识别成功')
// failArr.push(item)
fs.appendFileSync(failFilePath, `${item},\n`);
}
}).catch(function (err2) {
if (err2) {
console.log(err2);
cb(null, null);
}
});
})
到这里假如二维码清晰已经完成了,由于二维码的背景是个卡片,并且对比度不高,只扫出了三分之二,想着把图片处理以下
这里我又写了个脚本(用了python,现学现卖)
import cv2
import imutils
from skimage import measure
import numpy as np
import os
# 设置输入目录和输出目录
input_directory = './output_images' # 输入目录,包含图片的目录
output_directory = 'gray_img' # 输出目录,保存处理后的图片的目录
# 创建输出目录
if not os.path.exists(output_directory):
os.makedirs(output_directory)
# 获取输入目录中所有的图片文件
image_files = [f for f in os.listdir(input_directory) if f.lower().endswith(('.png', '.jpg', '.jpeg'))]
for image_file in image_files:
input_path = os.path.join(input_directory, image_file)
output_path = os.path.join(output_directory, image_file)
# 读取图像
image = cv2.imread(input_path)
image = cv2.resize(image, (1500, 1000))
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#ret, binary = cv2.threshold(gray, 135, 255, cv2.THRESH_BINARY)
cv2.imwrite(output_path, gray)
大功告成!
const fs=require('fs');
const resultFilePath='./chenggong.txt';
const failFilePath='./shibai.txt';
const filesList=fs.readdirSync('./output_images')
var jsqr=require('jsqr');
var Jimp=require('jimp');
let failArr=[
'0_1_2.png',
'10_1_2.png',
]
console.log(failArr.length);
// return
failArr.forEach((item, index) => {
var buffer=fs.readFileSync('./gray_img/'+item);
Jimp.read(buffer).then(function (blockimg) {
var width=blockimg.bitmap.width,
height=blockimg.bitmap.height,
imgData=blockimg.bitmap.data;
var code=jsqr(imgData, width, height,'invertFirst');
if (code) {
console.log(code.data);//内容
fs.appendFileSync(resultFilePath, `${item}: ${code.data},\n`);
} else {
console.log('未识别成功')
fs.appendFileSync(failFilePath, `${item},\n`);
}
}).catch(function (err2) {
if (err2) {
console.log(err2);
cb(null, null);
}
});
})