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

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

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

一、环境准备

  1. 添加Maven依赖
xml 复制代码
<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功能前,需要先加载本地库:

java 复制代码
static {
    // 加载OpenCV本地库 
    nu.pattern.OpenCV.loadLocally();
}

二、二维码生成工具类

java 复制代码
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());
    }
}

三、二维码识别工具类

java 复制代码
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();
    }
    
    /
     * 将OpenCV的Mat对象转换为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;
    }
}

四、使用示例

java 复制代码
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项目中二维码处理的需求。

相关推荐
Lxinccode17 分钟前
Java查询数据库表信息导出Word-获取数据库实现[1]:KingbaseES
java·数据库·word·获取数据库信息·获取kingbasees信息
元亓亓亓41 分钟前
Java后端开发day36--源码解析:HashMap
java·开发语言·数据结构
sd21315121 小时前
RabbitMQ 复习总结
java·rabbitmq
码银3 小时前
Java 集合:泛型、Set 集合及其实现类详解
java·开发语言
东阳马生架构3 小时前
Nacos简介—4.Nacos架构和原理
java
一只叫煤球的猫4 小时前
你真的会用 return 吗?—— 11个值得借鉴的 return 写法
java·后端·代码规范
zsffuture4 小时前
opencv 读取3G大图失败,又不想重新编译opencv ,可以如下操作
人工智能·opencv·webpack
颇有几分姿色4 小时前
Spring Boot 读取配置文件的几种方式
java·spring boot·后端
爱编程的鱼4 小时前
C# 枚举(Enum)声明与使用详解
java·windows·c#
人生导师yxc4 小时前
Spring MVC
java·spring·mvc