opencv结合微信二维码识别功能实现图片二维码识别

Posted luffy5459

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了opencv结合微信二维码识别功能实现图片二维码识别相关的知识,希望对你有一定的参考价值。

    opencv本身有二维码识别功能,但是识别效果不是很好,它对二维码图片要求较高,虽然可以有图片处理,甚至抠出二维码区域,但是整体识别与微信二维码识别功能还是有差距的。

    微信二维码识别,采用了机器学习算法,加入了CNN模型的概念,它作为三方库,开源给了opencv,而且支持java语言,不过要使用,需要结合操作系统做编译,需要下载opencv源码,还需要下载opencv_contrib代码,这里面就是一些三方库,微信二维码就在这里面。

    源码编译需要生成opencv_java45x.dll,opencv-java45x.so,opencv_java45x.jar等文件,不仅需要动态库,还需要jar包。

    在windows系统下,动态库是dll类型,在linux下动态库就是so类型。如果你能下载到opencv-4.x版本的jar,dll,so文件,可以直接使用,如果没有,就需要手动编译(编译过程非常复杂,建议不要轻易尝试)。

    有了jar,动态库,就很方便了,无需很复杂的设置,做过java开发的肯定知道jar需要加入类路径下,动态库只需要指定一个位置,java能像读文件一样加载到就可以了。

    这里以windows系统为例,所需的文件就是opencv-453.jar和opencv_java453.dll动态库,如果是maven项目,我们可以将opencv-java453.jar作为本地jar加入项目中。

<dependency>
      <groupId>org</groupId>
      <artifactId>opencv</artifactId>
      <version>453</version>
      <scope>system</scope>
      <systemPath>$project.basedir\\src\\main\\resources\\opencvlib\\opencv-453.jar</systemPath>
    </dependency>

   java代码如下:

package org.example;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.wechat_qrcode.WeChatQRCode;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.net.URL;
import java.util.List;

public class WeChatQRCodeTool 

    private static volatile  WeChatQRCodeTool instance;
    private static volatile WeChatQRCode detector;

    private WeChatQRCodeTool()
        System.setProperty("java.awt.headless","true");
        URL url = null;
        String os = System.getProperty("os.name");
        if(os.startsWith("Linux"))
            url = ClassLoader.getSystemResource("opencvlib/libopencv_java452.so");
            System.load(url.getPath());
            detector = new org.opencv.wechat_qrcode.WeChatQRCode();
        else
            url = ClassLoader.getSystemResource("opencvlib/opencv_java452.dll");
            System.load(url.getPath());
            ClassLoader cl = WeChatQRCodeTool.class.getClassLoader();
            URL detectprototxt = cl.getResource("opencvlib/detect.prototxt");
            URL detectcaffemodel =cl.getResource("opencvlib/detect.caffemodel");
            URL srprototxt=cl.getResource("opencvlib/sr.prototxt");
            URL srcaffemodel =cl.getResource("opencvlib/sr.caffemodel");
            detector = new org.opencv.wechat_qrcode.WeChatQRCode(
                    detectprototxt.getPath().substring(1),
                    detectcaffemodel.getPath().substring(1),
                    srprototxt.getPath().substring(1),
                    srcaffemodel.getPath().substring(1));
        
    

    public static WeChatQRCodeTool getInstance()
        if(instance==null)
            synchronized (WeChatQRCodeTool.class)
                if(instance==null)
                    instance = new WeChatQRCodeTool();
                
            
        
        return instance;
    

    public static Mat bufImg2Mat(BufferedImage original, int imgType, int matType) 
        if (original == null) 
            throw new IllegalArgumentException("original == null");
        
        byte[] pixels = null;
        // Don't convert if it already has correct type
        if (original.getType() != imgType) 

            // Create a buffered image
            BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), imgType);

            // Draw the image onto the new buffer
            Graphics2D g = image.createGraphics();
            try 
                g.setComposite(AlphaComposite.Src);
                g.drawImage(original, 0, 0, null);
                pixels = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
             finally 
                g.dispose();
            
         else 
            pixels = ((DataBufferByte) original.getRaster().getDataBuffer()).getData();
        
        Mat mat = Mat.eye(original.getHeight(), original.getWidth(), matType);
        mat.put(0, 0, pixels);
        return mat;
    

    public String decode(BufferedImage srcImage) 

        int cvtype = CvType.CV_8UC3;
        if(srcImage.getType() == BufferedImage.TYPE_BYTE_GRAY) 
            cvtype = CvType.CV_8UC1;
        
        Mat image = bufImg2Mat(srcImage, srcImage.getType(), cvtype);
        List<String> result2 = detector.detectAndDecode(image);
        if (result2 != null && result2.size() > 0) 
            return result2.get(0);
        
        return null;
    

    public String decodeQRCodeByPath(String qrCodePath)
        String qrCodeText = null;
        try 
            BufferedImage image = ImageIO.read(new File(qrCodePath));
            qrCodeText = decode(image);
        catch (Exception e)
            e.printStackTrace();
        
        return qrCodeText;
    


    public static void main(String[] args) 
        String img = "C:\\\\Users\\\\86159\\\\Pictures\\\\qr-3.jpg";
        String result = getInstance().decodeQRCodeByPath(img);
        System.out.println(result);
    

    示例图片如下:

 

    这个二维码图片,在一个大图中,人眼可以看,但是普通的二维码识别基本不可能识别,但是使用微信二维码识别,没有任何问题。识别结果如下所示:

 

    本人尝试过很多二维码图片,使用微信识别,基本一试一个准,果断放弃com.google.zxing提供的二维码识别功能。

    不得不佩服微信二维码识别功能的强大,再回过头来想想,这里面使用了深度学习的内容,比如CNN模型,虽然不懂,感觉已经很厉害了。

    本人在尝试过程中,发现,很多文章提到,Java使用微信二维码识别功能,需要下载模型文件,也就是代码中提到的:detect.prototxt,detect.caffemodel,sr.prototxt,sr.caffemodel文件,其实,不用这几个文件,也是可以的。

URL detectprototxt = cl.getResource("opencvlib/detect.prototxt");
URL detectcaffemodel =cl.getResource("opencvlib/detect.caffemodel");
URL srprototxt=cl.getResource("opencvlib/sr.prototxt");
URL srcaffemodel =cl.getResource("opencvlib/sr.caffemodel");
/*
detector = new org.opencv.wechat_qrcode.WeChatQRCode(
		detectprototxt.getPath().substring(1),
		detectcaffemodel.getPath().substring(1),
		srprototxt.getPath().substring(1),
		srcaffemodel.getPath().substring(1));*/
detector = new org.opencv.wechat_qrcode.WeChatQRCode();

    本文写到这里,其实也差不多了,但是这种识别只能在windows下,java开发,尤其是服务端,最后的代码99%都是部署在linux服务器下的,那么,本文介绍的办法无需改动,但是linux环境要求比较特殊。不仅需要opencv-453.jar,opencv_java453.so 文件,动态库在调用的时候,还需要一些其他的opencv依赖,这么一来,还是需要编译opencv+opencv_contrib。

   我在尝试部署到linux下发现,如果一个机器编译了so文件,可以复制到其他机器使用,其他机器就不需要编译了,但是这些动态库太多了,还是很麻烦的。

    本文代码以及所需资源都在这里:opencvtest: opencv结合微信二维码识别 (gitee.com)

以上是关于opencv结合微信二维码识别功能实现图片二维码识别的主要内容,如果未能解决你的问题,请参考以下文章

android 图片二维码识别和保存

ROS+opencv实践-二维码识别

微信小程序二维码识别

咸鱼教程Egret可长按识别二维码(精确位置和大小)

Jquery生成二维码(微信中长按图片识别二维码功能)

网页中如何用js实现微信中的长按识别二维码的功能吗