利用深度学习实现验证码识别-2-使用Python导出ONNX模型并在Java中调用实现验证码识别

news2024/11/13 11:17:58

在这里插入图片描述

1. Python部分:导出ONNX模型

首先,我们需要在Python中定义并导出一个已经训练好的验证码识别模型。以下是完整的Python代码:

import string
import torch
import torch.nn as nn
import torch.nn.functional as F

CHAR_SET = string.digits

# 优化后的模型设计
class CaptchaModel(nn.Module):
    def __init__(self):
        super(CaptchaModel, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, padding=1)
        self.conv2 = nn.Conv2d(32, 64, 3, padding=1)
        self.conv3 = nn.Conv2d(64, 128, 3, padding=1)
        self.fc1 = nn.Linear(128 * 5 * 12, 256)  # 调整为实际展平维度
        self.fc2 = nn.Linear(256, 4 * len(CHAR_SET))
        self.dropout = nn.Dropout(0.5)

    def forward(self, x):
        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2(x), 2))
        x = F.relu(F.max_pool2d(self.conv3(x), 2))
        x = x.view(x.size(0), -1)
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        x = self.fc2(x)
        return x.view(-1, 4, len(CHAR_SET))

# 使用CUDA,如果可用的话
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")
# 假设你的模型已经训练好并保存在 'best_model.pth'
model = CaptchaModel().to(device)
model.load_state_dict(torch.load('best_model.pth'))

# 生成一个测试输入 (示例输入的形状应与模型输入形状一致)
dummy_input = torch.randn(1, 1, 40, 100).to(device)

# 导出模型为 ONNX 格式
torch.onnx.export(model, dummy_input, "captcha_model.onnx", 
                  input_names=["input"], output_names=["output"], 
                  dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}})

print("Model exported to captcha_model.onnx")

这段代码定义了一个验证码识别模型,并将其导出为ONNX格式,以便在Java中使用。

2. Java部分:调用ONNX模型进行验证码识别

接下来,我们使用Java调用导出的ONNX模型进行验证码识别。以下是完整的Java代码:

  • 引用onnxruntime-1.19.0.jar
package com.tushuoit;

import ai.onnxruntime.*;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.List;

public class CaptchaInference {
    private static final String CHAR_SET = "0123456789";
    private static final int INPUT_WIDTH = 100;
    private static final int INPUT_HEIGHT = 40;
    private static final Random random = new Random();

    public static void main(String[] args) throws Exception {
        // 随机生成4个字符的验证码文本
        String captchaText = generateRandomText(4);
        System.out.println("Generated Captcha Text: " + captchaText);

        // 生成包含文本的Bitmap (BufferedImage)
        BufferedImage captchaImage = generateCaptcha(captchaText, 36, INPUT_WIDTH, INPUT_HEIGHT);

        // 将Bitmap保存为文件(仅用于查看生成的图像,实际使用中可以省略)
        ImageIO.write(captchaImage, "png", new File("generated_captcha.png"));

        // 将图像转换为浮点数数组,并进行归一化处理
        float[] inputData = imageToFloatArray(captchaImage);

        // 创建ONNX Runtime环境
        OrtEnvironment env = OrtEnvironment.getEnvironment();
        OrtSession.SessionOptions opts = new OrtSession.SessionOptions();

        // 加载ONNX模型
        OrtSession session = env.createSession("captcha_model.onnx", opts);

        // 创建输入张量
        FloatBuffer inputBuffer = FloatBuffer.wrap(inputData);
        OnnxTensor inputTensor = OnnxTensor.createTensor(env, inputBuffer,
                new long[] { 1, 1, INPUT_HEIGHT, INPUT_WIDTH });

        // 进行推理
        OrtSession.Result result = session.run(Collections.singletonMap("input", inputTensor));

        // Extract output tensor and decode it
        float[][][] outputData = (float[][][]) result.get(0).getValue();
        List<String> decodedTexts = decodeOutput(outputData);

        // Print the decoded captcha text
        for (String text : decodedTexts) {
            System.out.println("Predicted Captcha Text: " + text);
        }

        System.out.println("Inference completed.");
        // 释放资源
        session.close();
        env.close();
    }

    // 随机生成指定长度的验证码文本
    private static String generateRandomText(int length) {
        StringBuilder text = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            text.append(CHAR_SET.charAt(random.nextInt(CHAR_SET.length())));
        }
        return text.toString();
    }

    // 生成包含文本的BufferedImage
    private static BufferedImage generateCaptcha(String text, int fontSize, int width, int height) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = image.createGraphics();

        // 设置背景颜色为白色
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, width, height);

        // 设置字体和颜色
        g2d.setFont(new Font("DroidSansMono", Font.PLAIN, fontSize));
        g2d.setColor(Color.BLACK);

        // 绘制文本
        FontMetrics fm = g2d.getFontMetrics();
        int x = 5; // 文字开始的X坐标
        int y = fm.getAscent() + 5; // 文字开始的Y坐标
        g2d.drawString(text, x, y);

        g2d.dispose();
        return image;
    }

    // 将BufferedImage转换为float数组,并进行归一化处理
    private static float[] imageToFloatArray(BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();
        float[] floatArray = new float[width * height];

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int rgb = image.getRGB(x, y);
                int gray = (rgb >> 16) & 0xFF; // 因为是灰度图,只需获取一个通道的值
                floatArray[y * width + x] = (gray / 255.0f - 0.5f) * 2.0f; // 归一化到[-1, 1]
            }
        }

        return floatArray;
    }

    private static List<String> decodeOutput(float[][][] outputData) {
        List<String> decodedTexts = new ArrayList<>();
        for (float[][] singleOutput : outputData) {
            StringBuilder decodedText = new StringBuilder();
            for (float[] charProbabilities : singleOutput) {
                int maxIndex = getMaxIndex(charProbabilities);
                decodedText.append(CHAR_SET.charAt(maxIndex));
            }
            decodedTexts.add(decodedText.toString());
        }
        return decodedTexts;
    }

    private static int getMaxIndex(float[] probabilities) {
        int maxIndex = 0;
        float maxProb = probabilities[0];
        for (int i = 1; i < probabilities.length; i++) {
            if (probabilities[i] > maxProb) {
                maxProb = probabilities[i];
                maxIndex = i;
            }
        }
        return maxIndex;
    }
}

这段Java代码首先生成一个随机的验证码图像,然后将其转换为模型输入格式,并通过ONNX Runtime调用导出的模型进行推理,最后解码模型的输出以获取识别的验证码文本。
在这里插入图片描述

总结

通过上述步骤,我们成功地在Python中导出了一个验证码识别模型,并在Java中调用该模型进行验证码识别。这种方法充分利用了Python在深度学习模型训练和导出方面的优势,以及Java在实际应用部署和性能方面的优势,实现了高效的验证码识别系统。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2095525.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

静态库和共享库

文章目录 库的概念函数库库函数静态库的创建与使用静态库的概念静态库的创建代码示例--静态库的创建和使用 共享库的创建和是使用共享库的概念共享库的创建共享库的使用 总结 库的概念 当进行编辑C代码的时候常常会用到printf函数&#xff0c;这个函数被声明在stdio.h头文件中…

企业内部通信软件:打造高效协同办公的IM即时通讯工具

在现代企业中&#xff0c;高效的内部通信和协同办公是保持竞争优势的重要因素。为了实现团队间的快速沟通和协作&#xff0c;许多企业采用了企业内部通信软件&#xff0c;其中包括IM即时通讯工具。本文将探讨企业内部通信软件的重要性以及如何利用IM即时通讯工具打造高效协同办…

Clickhouse 为什么这么快

Clickhouse 的缘起 Clickhouse 最初是为 Yandex.Metrica 这个世界上第二大的Web分析平台开发的&#xff0c;并且一直是这个系统的核心组件。ClickHouse在Yandex.Metrica中的主要任务是使用非聚合数据在在线模式下构建报告&#xff0c;使用374台服务器组成的集群&#xff0c;在…

服务器间进行文件传输-SFTPSCP一篇搞定

1.简单介绍一下 在一些特殊场景&#xff0c;两台服务器之间需要进行文件传输的时候&#xff0c;或许我们会想到FTP&#xff0c;这也是我们常见的实现方式&#xff0c;但是如果我们不能操作远程服务器&#xff0c;无法判断远程服务器是否安装了FTP呢&#xff0c;众所周知&#…

学习周报-2024.8.31

目录 摘要 Abstract 创新点总结 模型数学原理 实验设置 一、验证实验 二、对比实验 摘要 这周重新梳理出论文的三个创新点&#xff0c;对所提出方法进行数学原理验证&#xff0c;证明其可行性。重新设置了实验部分&#xff0c;分为验证实验和对比实验&#xff0c;一共四…

使用 Eigen 库中的 Kronecker 积运算

前言 在数值计算和线性代数的众多应用中&#xff0c;Kronecker 积&#xff08;Kronecker Product&#xff09;是一种常用的矩阵运算。Eigen 是一个高性能的 C 数值计算库&#xff0c;广泛用于科学计算和工程应用中。在 Eigen 库中&#xff0c;Kronecker 积运算属于不常用的扩展…

资料分析(1)

1)截三个数去做&#xff0c;属于马上进位了&#xff0c;差距小&#xff0c;1/19<10% 2)截两位数去做&#xff0c;1/18>10% 3)次位差分别是:3&#xff0c;4&#xff0c;1&#xff0c;选项差距分别是大&#xff0c;大&#xff0c;小 截尾不需要考虑数量级 算一半&#xff0…

抽奖项目技术亮点

活动是通过秒杀领取的。&#xff08;即&#xff1a;活动对应着某一商品&#xff09; 这里超卖指&#xff1a;对于一个活动它的参与量有数量限制&#xff0c;就是活动的库存&#xff0c;当活动的领取数大于活动库存总量&#xff0c;就是超卖 用户秒杀参与活动的资格&#xff08;…

一.海量数据实时分析-Doris入门和安装

前言 停了一个月又开始写文章啦&#xff0c;因为公司数据量达到了几十亿&#xff0c;老板需要做实时数据分析&#xff0c;报表看板。这么大的数据量比较好的选择是使用Doris来做&#xff0c;他可以脱离hadoop生态独立使用所以大受企业喜爱&#xff0c;也因为如此就有了这个系列…

【JavaWeb】Http请求与响应

文章目录 Http 请求与响应一、Http 请求格式1、请求行2、请求头3、请求体&#xff08;post请求才有&#xff09; 二、HttpServletRequest1、获取 请求行 信息2、获取 请求头 信息3、获取 请求参数 信息 三、Http 响应格式1、响应行2、响应头3、响应体&#xff08;正文&#xff…

AI大模型应用开发环境配置

目录 一、工具下载 1、Python官网下载 2、Pycharm官网下载 3、Streamlit官网下载 二、升级PIP &#xff08;一&#xff09;检查PIP版本 &#xff08;二&#xff09;在anaconda Prompt命令窗口输入 三、安装openai组件 四、安装streamlit组件 五、启动streamlit 一、工…

Voi滑板车公司助农扶商,着手打造流量板块

Voi滑板车公司助农扶商&#xff0c;着手打造流量板块。 吉林是粮食大省&#xff0c;是全国优质粳稻主产区&#xff0c;现阶段全省水稻年产量600多万吨&#xff08;商品量400万吨左右&#xff09;&#xff0c;占东北三省一区的24%。巍巍长白山、悠悠松江水&#xff0c;辽阔黑土…

Qt:玩转QPainter序列九(文本,文本框,填充)

前言 继续承接序列八 正文 1. drawImage系列函数 绘制图像 inline void drawImage(const QPoint &p, const QImage &image); 作用: 在指定的点 p 上绘制 QImage 图像。图像的左上角将对齐到 p 点。 inline void drawImage(int x, int y, const QImage &image,…

若依 Vue3的前后端分离系统管理 创建

RuoYi 若依官方网站 |后台管理系统|权限管理系统|快速开发框架|企业管理系统|开源框架|微服务框架|前后端分离框架|开源后台系统|RuoYi|RuoYi-Vue|RuoYi-Cloud|RuoYi框架|RuoYi开源|RuoYi视频|若依视频|RuoYi开发文档|若依开发文档|Java开源框架|Java|SpringBoot|SrpingBoot2.0…

【JPCS独立出版】第四届电气工程与计算机技术国际学术会议(ICEECT 2024,9月27-29)

第四届电气工程与计算机技术国际学术会议&#xff08;ICEECT2024&#xff09;将于9月27日-29日在哈尔滨举办。 会议主要围绕"电路与系统"、“电气工程材料”、“计算机视觉”、“计算机技术”等专业研究领域展开讨论。旨在为气工程、计算机技术等领域的专家学者及企业…

Java EE

Java EE 包含JavaSE 增加一些新的API 构建一个后端服务 网页->web服务器->java后端 web后端(javaEE)程序需要运行在服务器中的&#xff0c;这样前端才可以访问得到 服务器&#xff1a;是容器&#xff0c;是连接用户和程序之间的中间件 解释1&#xff1a;一款软件&#…

HBase 部署及shell操作

HBase 数据库 一、HBase 概述1.1 HBase 是什么HBase 的特点 二、HBase 模型及架构2.1 HBase 逻辑模型2.2 HBase 数据模型2.3 HBase 物理模型2.3.1 列簇物理模型2.3.2 Rowkey 字段排序2.3.3 Region 存储到不同节点2.3.4 Region 结构 2.4 HBase 基本架构 三、搭建 HBase 分布式集…

【Linux】线程结束

目录 线程安全和重入 死锁 STL中的容器不是线程安全的 线程安全的单例模式 自旋锁 读者写者问题 线程安全和重入 线程安全&#xff1a;多个线程并发执行同一段代码时&#xff0c;不会出现不同的&#xff08;异常的&#xff09;结果&#xff0c;我们就说线程是安全的。常见…

如何学好文件操作,快来看这篇文章(沉淀中)!!!!

文章目录 1. 为什么使用文件&#xff1f;2. 什么是文件&#xff1f;2.1 程序文件2.2 数据文件2.3 文件名 3. ⼆进制文件和文本文件&#xff1f;4. 文件的打开和关闭4.1 流和标准流4.1.1 流4.1.2 标准流 4.2 文件指针4.3 文件的打开和关闭 5. ⽂件的顺序读写5.1 顺序读写函数介绍…

jQuery库

注明&#xff1a;本文参考自&#xff1a;jQuery - 白月黑羽 (byhy.net) jQuery安装 Download jQuery | jQuery下载到本地 ps: script标签中的src属性&#xff1a;表示包含要执行的代码的外部文件位置 <!DOCTYPE html> <html lang"en"><head><s…