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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LOVE_DDZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值