用 JavaScript 和 TensorFlow.js 实现图像验证码识别

本教程介绍如何使用前端技术(JavaScript + TensorFlow.js)实现一个简单的图像验证码识别系统,适用于浏览器或 Node.js 环境。

  1. 准备环境
    确保你安装了 Node.js 和相关依赖。

npm install @tensorflow/tfjs-node canvas
2. 准备训练数据
你可以使用 Python 脚本生成图像验证码数据(与之前相同):

from captcha.image import ImageCaptcha
import random, string, os
更多内容访问ttocr.com或联系1436423940
characters = string.digits + string.ascii_uppercase
generator = ImageCaptcha(width=160, height=60)
os.makedirs("js_captcha", exist_ok=True)

for i in range(5000):
text = ''.join(random.choices(characters, k=4))
image = generator.generate_image(text)
image.save(f"js_captcha/{text}_{i}.png")
3. 加载图片与标签

const fs = require('fs');
const tf = require('@tensorflow/tfjs-node');
const { createCanvas, loadImage } = require('canvas');

const characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const charToIndex = Object.fromEntries(characters.split('').map((c, i) => [c, i]));

async function loadCaptcha(filePath) {
const image = await loadImage(filePath);
const canvas = createCanvas(160, 60);
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0, 160, 60);
const data = ctx.getImageData(0, 0, 160, 60).data;

const input = [];
for (let i = 0; i < data.length; i += 4) {
input.push(data[i] / 255); // 使用 R 通道
}

const label = filePath.split('/').pop().split('_')[0].split('').map(c => charToIndex[c]);

return { input, label };
}
4. 构建模型结构

function buildModel() {
const model = tf.sequential();

model.add(tf.layers.dense({ inputShape: [160 * 60], units: 512, activation: 'relu' }));
model.add(tf.layers.dropout({ rate: 0.3 }));
model.add(tf.layers.dense({ units: 4 * characters.length, activation: 'softmax' }));

model.compile({
optimizer: tf.train.adam(0.001),
loss: 'categoricalCrossentropy',
metrics: ['accuracy']
});

return model;
}
注意:输出层大小为 36 × 4 = 144,将每个字符的位置展开。

  1. 训练模型

async function trainModel(model, inputs, labels) {
const xs = tf.tensor2d(inputs);
const ys = tf.tensor2d(labels);

await model.fit(xs, ys, {
batchSize: 64,
epochs: 10,
callbacks: tf.callbacks.earlyStopping({ monitor: 'loss', patience: 2 })
});
}
你需要将标签转为 one-hot 编码格式:

function oneHotLabel(label) {
const result = new Array(characters.length * 4).fill(0);
label.forEach((charIdx, i) => {
result[i * characters.length + charIdx] = 1;
});
return result;
}
6. 预测验证码

async function predict(model, filePath) {
const { input } = await loadCaptcha(filePath);
const prediction = model.predict(tf.tensor2d([input]));
const values = prediction.dataSync();

const result = [];
for (let i = 0; i < 4; i++) {
const slice = values.slice(i * characters.length, (i + 1) * characters.length);
const index = slice.indexOf(Math.max(...slice));
result.push(characters[index]);
}

console.log('Predicted:', result.join(''));
}

posted @ 2025-05-26 18:24  ttocr、com  阅读(56)  评论(0)    收藏  举报