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.pswp.cn/bicheng/78423.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78423.shtml
英文地址,請注明出處:http://en.pswp.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 配置文件 創建…