Java集成Zxing和OpenCV实现二维码生成与识别工具类

Java集成Zxing和OpenCV实现二维码生成与识别工具类

本文将介绍如何使用Java集成Zxing和OpenCV库,实现二维码的生成和识别功能。识别方法支持多种输入形式,包括File对象、文件路径和Base64编码。

一、环境准备

  1. 添加Maven依赖
<dependencies><!-- Zxing核心库 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.2</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.5.2</version></dependency><!-- OpenCV库 --><dependency><groupId>org.openpnp</groupId><artifactId>opencv</artifactId><version>4.5.5-1</version></dependency><!-- 其他工具类 --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency>
</dependencies>
  1. OpenCV库加载

在使用OpenCV功能前,需要先加载本地库:

static {// 加载OpenCV本地库 nu.pattern.OpenCV.loadLocally();
}

二、二维码生成工具类

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;public class QRCodeGenerator {private static final int DEFAULT_WIDTH = 300;private static final int DEFAULT_HEIGHT = 300;private static final String DEFAULT_FORMAT = "png";/* 生成二维码图片 * @param content 二维码内容 * @param width 宽度 * @param height 高度 * @return BufferedImage对象 */public static BufferedImage generateQRCodeImage(String content, int width, int height) throws WriterException {Map<EncodeHintType, Object> hints = new HashMap<>();hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);hints.put(EncodeHintType.MARGIN, 1);hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");QRCodeWriter qrCodeWriter = new QRCodeWriter();BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);return MatrixToImageWriter.toBufferedImage(bitMatrix);}/* 生成二维码并保存到文件 * @param content 二维码内容 * @param width 宽度 * @param height 高度 * @param filePath 文件路径 */public static void generateQRCodeToFile(String content, int width, int height, String filePath) throws WriterException, IOException {BufferedImage image = generateQRCodeImage(content, width, height);ImageIO.write(image, DEFAULT_FORMAT, new File(filePath));}/* 生成二维码并返回Base64编码 * @param content 二维码内容 * @param width 宽度 * @param height 高度 * @return Base64编码字符串 */public static String generateQRCodeToBase64(String content, int width, int height) throws WriterException, IOException {BufferedImage image = generateQRCodeImage(content, width, height);ByteArrayOutputStream os = new ByteArrayOutputStream();ImageIO.write(image, DEFAULT_FORMAT, os);return Base64.getEncoder().encodeToString(os.toByteArray());}
}

三、二维码识别工具类

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Base64;
import java.util.EnumMap;
import java.util.Map;public class QRCodeRecognizer {static {// 加载OpenCV本地库 nu.pattern.OpenCV.loadLocally();}/* 识别二维码内容 - 通过File对象 * @param file 二维码图片文件 * @return 识别结果 */public static String recognizeQRCode(File file) throws IOException, NotFoundException {BufferedImage image = ImageIO.read(file);return decodeQRCode(image);}/* 识别二维码内容 - 通过文件路径 * @param filePath 二维码图片路径 * @return 识别结果 */public static String recognizeQRCode(String filePath) throws IOException, NotFoundException {// 使用OpenCV预处理图像提高识别率 Mat image = Imgcodecs.imread(filePath);if (image.empty()) {throw new IOException("无法读取图像文件: " + filePath);}// 转换为灰度图 Mat gray = new Mat();Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);// 二值化处理 Mat binary = new Mat();Imgproc.threshold(gray, binary, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);// 转换为BufferedImage BufferedImage bufferedImage = matToBufferedImage(binary);return decodeQRCode(bufferedImage);}/* 识别二维码内容 - 通过Base64编码 * @param base64Str 二维码图片的Base64编码 * @return 识别结果 */public static String recognizeQRCodeFromBase64(String base64Str) throws IOException, NotFoundException {byte[] imageBytes = Base64.getDecoder().decode(base64Str);ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes);BufferedImage image = ImageIO.read(bis);return decodeQRCode(image);}/* 核心解码方法 */private static String decodeQRCode(BufferedImage image) throws NotFoundException {LuminanceSource source = new BufferedImageLuminanceSource(image);BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");Result result = new MultiFormatReader().decode(bitmap, hints);return result.getText();}/*OpenCVMat对象转换为BufferedImage */private static BufferedImage matToBufferedImage(Mat mat) {int type = BufferedImage.TYPE_BYTE_GRAY;if (mat.channels() > 1) {type = BufferedImage.TYPE_3BYTE_BGR;}byte[] data = new byte[mat.cols() * mat.rows() * (int)mat.elemSize()];mat.get(0, 0, data);BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);image.getRaster().setDataElements(0, 0, mat.cols(), mat.rows(), data);return image;}
}

四、使用示例

public class QRCodeExample {public static void main(String[] args) {try {// 1. 生成二维码 String content = "https://www.example.com";String filePath = "qrcode.png";// 生成并保存二维码 QRCodeGenerator.generateQRCodeToFile(content, 300, 300, filePath);System.out.println("二维码已生成到: " + filePath);// 2. 识别二维码 - 通过File对象 File qrFile = new File(filePath);String decodedContent1 = QRCodeRecognizer.recognizeQRCode(qrFile);System.out.println("识别结果(File): " + decodedContent1);// 3. 识别二维码 - 通过文件路径 String decodedContent2 = QRCodeRecognizer.recognizeQRCode(filePath);System.out.println("识别结果(文件路径): " + decodedContent2);// 4. 识别二维码 - 通过Base64 String base64 = QRCodeGenerator.generateQRCodeToBase64(content, 300, 300);String decodedContent3 = QRCodeRecognizer.recognizeQRCodeFromBase64(base64);System.out.println("识别结果(Base64): " + decodedContent3);} catch (Exception e) {e.printStackTrace();}}
}

五、关键点说明

  1. OpenCV预处理:在识别二维码时,使用OpenCV对图像进行灰度化和二值化处理,可以显著提高识别率,特别是对低质量或模糊的二维码图像。

  2. 多输入支持:识别方法支持三种输入形式:

    • File对象:直接读取文件
    • 文件路径:使用OpenCV读取并预处理
    • Base64编码:适用于网络传输的场景
  3. 错误处理:方法会抛出IOExceptionNotFoundException,调用方需要处理这些异常。

  4. 性能优化:

    • 使用TRY_HARDER提示让解码器更努力尝试解码
    • 指定字符集为UTF-8确保中文内容正确识别
    • OpenCV的预处理可以有效提高识别率

六、扩展建议

  1. 添加Logo:可以在生成二维码时添加中心Logo,增强品牌识别度。

  2. 颜色定制:修改生成方法支持自定义前景色和背景色。

  3. 批量处理:扩展工具类支持批量生成和识别二维码。

  4. 性能监控:添加耗时统计和性能监控功能。

这个工具类结合了Zxing的高效二维码生成/识别能力和OpenCV强大的图像处理能力,可以满足大多数Java项目中二维码处理的需求。

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

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

相关文章

【专题刷题】二分查找(二)

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码&#xff1b;&#xff…

Java—ThreadLocal底层实现原理

首先&#xff0c;ThreadLocal 本身并不提供存储数据的功能&#xff0c;当我们操作 ThreadLocal 的时候&#xff0c;实际上操作线程对象的一个名为 threadLocals 成员变量。这个成员变量的类型是 ThreadLocal 的一个内部类 ThreadLocalMap&#xff0c;它是真正用来存储数据的容器…

Elasticsearch(ES)中的脚本(Script)

文章目录 一. 脚本是什么&#xff1f;1. lang&#xff08;脚本语言&#xff09;2. source&#xff08;脚本代码&#xff09;3. params&#xff08;参数&#xff09;4. id&#xff08;存储脚本的标识符&#xff09;5. stored&#xff08;是否为存储脚本&#xff09;6. script 的…

客户联络中心能力与客户匹配方式

在数字化时代&#xff0c;客户联络中心作为企业与客户沟通的核心枢纽&#xff0c;其服务能力与客户需求的精准匹配至关重要。随着客户期望的不断提升&#xff0c;传统的“一刀切”服务模式已难以满足个性化需求&#xff0c;如何通过智能化的手段实现服务能力与客户的高效匹配&a…

深入理解网络原理:UDP协议详解

在计算机网络中&#xff0c;数据的传输是通过各种协议实现的&#xff0c;其中用户数据报协议&#xff08;UDP&#xff0c;User Datagram Protocol&#xff09;作为一种重要的传输层协议&#xff0c;广泛应用于实时通信、视频流、在线游戏等场景。本文将深入探讨UDP协议的特性、…

vscode切换Python环境

跑深度学习项目通常需要切换python环境&#xff0c;下面介绍如何在vscode切换python环境&#xff1a; 1.点击vscode界面左上角 2.在弹出框选择对应kernel

【MCP Node.js SDK 全栈进阶指南】中级篇(4):MCP错误处理与日志系统

前言 随着MCP应用的规模和复杂性增长,错误处理与日志系统的重要性也日益凸显。一个健壮的错误处理策略和高效的日志系统不仅可以帮助开发者快速定位和解决问题,还能提高应用的可靠性和可维护性。本文作为中级篇的第四篇,将深入探讨MCP TypeScript-SDK中的错误处理与日志系统…

【Qt】文件

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Qt 目录 一&#xff1a;&#x1f525; Qt 文件概述 二&#xff1a;&#x1f525; 输入输出设备类 三&#xff1a;&#x1f525; 文件读写类 四&#xff1a;&#x1f525; 文件和目录信息类 五&…

代码随想录算法训练营第五十八天 | 1.拓扑排序精讲 2.dijkstra(朴素版)精讲 卡码网117.网站构建 卡码网47.参加科学大会

1.拓扑排序精讲 题目链接&#xff1a;117. 软件构建 文章讲解&#xff1a;代码随想录 思路&#xff1a; 把有向无环图进行线性排序的算法都可以叫做拓扑排序。 实现拓扑排序的算法有两种&#xff1a;卡恩算法&#xff08;BFS&#xff09;和DFS&#xff0c;以下BFS的实现思…

Qt实现语言切换的完整方案

在Qt中实现语言动态切换需要以下几个关键步骤&#xff0c;我将提供一个完整的实现方案&#xff1a; 一、准备工作 在代码中使用tr()标记所有需要翻译的字符串 cpp button->setText(tr("Submit")); 创建翻译文件 在.pro文件中添加&#xff1a; qmake TRANSLATION…

面试中被问到mybatis与jdbc有什么区别怎么办

1. 核心区别 维度JDBCMyBatis抽象层级底层API&#xff0c;直接操作数据库高层持久层框架&#xff0c;封装JDBC细节代码量需要手动编写大量样板代码&#xff08;连接、异常处理等&#xff09;通过配置和映射减少冗余代码SQL管理SQL嵌入Java代码&#xff0c;维护困难SQL与Java代…

用于协同显著目标检测的小组协作学习 2021 GCoNet(总结)

摘要 一 介绍 问题一&#xff1a;以往的研究尝试利用相关图像之间的一致性&#xff0c;通过探索不同的共享线索[12, 13, 14]或语义连接[15, 16, 17]&#xff0c;来助力图像组内的共同显著目标检测&#xff08;CoSOD&#xff09;&#xff0c;什么意思&#xff1f; 一方面是探…

OpenCV 图形API(62)特征检测-----在图像中查找最显著的角点函数goodFeaturesToTrack()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 确定图像上的强角点。 该函数在图像或指定的图像区域内找到最显著的角点&#xff0c;如文献[240]中所述。 函数使用 cornerMinEigenVal 或 cor…

MySQL引擎分类与选择、SQL更新底层实现、分库分表、读写分离、主从复制 - 面试实战

MySQL引擎分类与选择、SQL更新底层实现、分库分表、读写分离、主从复制 - 面试实战 故事背景&#xff1a; 今天&#xff0c;我们模拟一场互联网大厂Java求职者的面试场景。面试官将针对MySQL的核心技术点进行提问&#xff0c;涵盖MySQL引擎分类与选择、SQL更新底层实现、分库…

如何确保微型导轨的质量稳定?

微型导轨在精密机械中扮演着至关重要的角色&#xff0c;它们不仅影响设备的性能&#xff0c;还决定了产品的寿命。那么&#xff0c;如何通过一些关键步骤来提高微型导轨的稳定性呢&#xff1f; 1、严格筛选供应商&#xff1a;选择具备高品质保证能力的供应商&#xff0c;确保原…

Golang编程拒绝类型不安全

简介 在 Go 中&#xff0c;标准库提供了多种容器类型&#xff0c;如 list、ring、heap、sync.Pool 和 sync.Map。然而&#xff0c;这些容器默认是类型不安全的&#xff0c;即它们可以接受任何类型的值&#xff0c;这可能导致运行时错误。为了提升代码的类型安全性和可维护性&am…

什么是 JSON?学习JSON有什么用?在springboot项目里如何实现JSON的序列化和反序列化?

作为一个学习Javaweb的新手&#xff0c;理解JSON的序列化和反序列化非常重要&#xff0c;因为它在现代Web开发&#xff0c;特别是Spring Boot中无处不在。 什么是 JSON&#xff1f; 首先&#xff0c;我们简单了解一下JSON (JavaScript Object Notation)。 JSON 是一种轻量级的…

iOS/Android 使用 C++ 跨平台模块时的内存与生命周期管理

在移动应用开发领域,跨平台开发已经成为一种不可忽视的趋势。随着智能手机市场的持续扩张,开发者需要同时满足iOS和Android两大主流平台的需求,而这往往意味着重复的工作量和高昂的维护成本。跨平台开发的目标在于通过一套代码库实现多平台的支持,从而降低开发成本、加速产…

【AAudio】A2dp sink创建音频轨道的源码流程分析

一、AAudio概述 AAudio 是 Android 8.0(API 级别 26)引入的 C/C++ 原生音频 API,专为需要低延迟、高性能音频处理的应用设计,尤其适用于实时音频应用(如音频合成器、音乐制作工具、游戏音效等)。 1.1 主要特点 低延迟:通过减少音频数据在内核与用户空间之间的拷贝,直…

Spring中配置 Bean 的两种方式:XML 配置 和 Java 配置类

在 Spring 框架中,配置 Bean 的方式主要有两种:XML 配置 和 Java 配置类。这两种方式都可以实现将对象注册到 Spring 容器中,并通过依赖注入进行管理。本文将详细介绍这两种配置方式的步骤,并提供相应的代码示例。 1. 使用 XML 配置的方式 步骤 创建 Spring 配置文件 创建…