5-QR code识别

1-简介

OPENCV中对于QR code的识别有四种方法:
1、方法一:使用OPENCV模块中的QRCodeDetector(opencv版本在4以上)
2、方法二:使用OPENCV外部contrib中的wechat_qrcode外部模块(OpenCV4.5及以上)
3、方法三:根据QR code的编码原理从底层解析QR code
4、方法四:采用第三方zBar库

2-方法一:QRCodeDetector

一、源代码
OpenCV在对象检测模块中QRCodeDetector有两个相关API分别实现二维码检测与二维码解析:

/** @brief Detects QR code in image and returns the quadrangle containing the code.
     @param img grayscale or color (BGR) image containing (or not) QR code.
     @param points Output vector of vertices of the minimum-area quadrangle containing the code.
     */
    CV_WRAP bool detect(InputArray img, OutputArray points) const;

    /** @brief Decodes QR code in image once it's found by the detect() method.

     Returns UTF8-encoded output string or empty string if the code cannot be decoded.
     @param img grayscale or color (BGR) image containing QR code.
     @param points Quadrangle vertices found by detect() method (or some other algorithm).
     @param straight_qrcode The optional output image containing rectified and binarized QR code
     */
    CV_WRAP std::string decode(InputArray img, InputArray points, OutputArray straight_qrcode = noArray());

    /** @brief Decodes QR code on a curved surface in image once it's found by the detect() method.

     Returns UTF8-encoded output string or empty string if the code cannot be decoded.
     @param img grayscale or color (BGR) image containing QR code.
     @param points Quadrangle vertices found by detect() method (or some other algorithm).
     @param straight_qrcode The optional output image containing rectified and binarized QR code
     */
    CV_WRAP cv::String decodeCurved(InputArray img, InputArray points, OutputArray straight_qrcode = noArray());

    /** @brief Both detects and decodes QR code

     @param img grayscale or color (BGR) image containing QR code.
     @param points optional output array of vertices of the found QR code quadrangle. Will be empty if not found.
     @param straight_qrcode The optional output image containing rectified and binarized QR code
     */
    CV_WRAP std::string detectAndDecode(InputArray img, OutputArray points=noArray(),
                                        OutputArray straight_qrcode = noArray());

    /** @brief Both detects and decodes QR code on a curved surface

     @param img grayscale or color (BGR) image containing QR code.
     @param points optional output array of vertices of the found QR code quadrangle. Will be empty if not found.
     @param straight_qrcode The optional output image containing rectified and binarized QR code
     */
    CV_WRAP std::string detectAndDecodeCurved(InputArray img, OutputArray points=noArray(),
                                              OutputArray straight_qrcode = noArray());

    /** @brief Detects QR codes in image and returns the vector of the quadrangles containing the codes.
     @param img grayscale or color (BGR) image containing (or not) QR codes.
     @param points Output vector of vector of vertices of the minimum-area quadrangle containing the codes.
     */
    CV_WRAP
    bool detectMulti(InputArray img, OutputArray points) const;

    /** @brief Decodes QR codes in image once it's found by the detect() method.
     @param img grayscale or color (BGR) image containing QR codes.
     @param decoded_info UTF8-encoded output vector of string or empty vector of string if the codes cannot be decoded.
     @param points vector of Quadrangle vertices found by detect() method (or some other algorithm).
     @param straight_qrcode The optional output vector of images containing rectified and binarized QR codes
     */
    CV_WRAP
    bool decodeMulti(
            InputArray img, InputArray points,
            CV_OUT std::vector<std::string>& decoded_info,
            OutputArrayOfArrays straight_qrcode = noArray()
    ) const;

    /** @brief Both detects and decodes QR codes
    @param img grayscale or color (BGR) image containing QR codes.
    @param decoded_info UTF8-encoded output vector of string or empty vector of string if the codes cannot be decoded.
    @param points optional output vector of vertices of the found QR code quadrangles. Will be empty if not found.
    @param straight_qrcode The optional output vector of images containing rectified and binarized QR codes
    */
    CV_WRAP
    bool detectAndDecodeMulti(
            InputArray img, CV_OUT std::vector<std::string>& decoded_info,
            OutputArray points = noArray(),
            OutputArrayOfArrays straight_qrcode = noArray()
    ) const;

二、示例代码:

// qrcodeDetecte.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include 
#include 

using namespace std;
using namespace cv;

int main()
{
	Mat src = imread("D:/C++Working/image/qrImage2.JPG");
	if (src.empty()) {
		return -1;
	}
	imshow("src image", src);

	QRCodeDetector detecter;

	vector<string> urlList;
	vector<Point> pointsList;
	detecter.detectAndDecodeMulti(src, urlList, pointsList);
	int j = 0;
	for (size_t i = 0; i < urlList.size(); i++)
	{
		Point pt1 = pointsList[j];
		Point pt2 = pointsList[j+1];
		Point pt3 = pointsList[j+2];
		Point pt4 = pointsList[j+3];
		line(src, pt1, pt2, Scalar(0, 255, 0), 2);
		line(src, pt2, pt3, Scalar(0, 255, 0), 2);
		line(src, pt3, pt4, Scalar(0, 255, 0), 2);
		line(src, pt4, pt1, Scalar(0, 255, 0), 2);
		
		putText(src, urlList[i], pt1, 0, 0.5, Scalar(255, 0, 0), 2);
		j = j + 4;
	}


	imshow("result image", src);
	waitKey(0);
	return 0;
}



三、结果:
5-QR code识别_第1张图片

四、结论
从检测结果上,该方法至少存在1个致命缺陷:
1、会出现漏检情况()
2、QR code存储内容太长也会出现漏检

3-方法二:wechat_qrcode

微信开源了QRCode解码功能,OPENCV可以通过添加外部库的方法使用该模块:
一、配置方法

WeChatQRCode模块为OpenCV4.5.1新增功能,需要在github下载最新opencv源码master和contrib部分编译后使用。
源码编译使用CMake,相关编译教程很多博客写的很详细,这里只做关键步骤说明:
(1) 编译是勾选BUILD_opencv_wechat_qrcode选项(默认勾选)
5-QR code识别_第2张图片
(2) 勾选BUILD_opencv_world 这样只生成一个dll方便使用
5-QR code识别_第3张图片
(3) 先Configure,后Generate,直至不报错(警告可忽略)
(4) 打开OpenCV.Sln,先生成ALLBuild,再仅用于项目生成Install,生成成功(无错误,无失败)会得到如下文件:
5-QR code识别_第4张图片
5-QR code识别_第5张图片
5-QR code识别_第6张图片
5-QR code识别_第7张图片
接下来就是配置步骤:包含目录、库目录、附加依赖项和环境变量,这个大家用这么久OpenCV应该都会了,这里跳过。

二、源代码

class CV_EXPORTS_W WeChatQRCode {
public:
    /**
     * @brief Initialize the WeChatQRCode.
     * It includes two models, which are packaged with caffe format.
     * Therefore, there are prototxt and caffe models (In total, four paramenters).
     *
     * @param detector_prototxt_path prototxt file path for the detector
     * @param detector_caffe_model_path caffe model file path for the detector
     * @param super_resolution_prototxt_path prototxt file path for the super resolution model
     * @param super_resolution_caffe_model_path caffe file path for the super resolution model
     */
    CV_WRAP WeChatQRCode(const std::string& detector_prototxt_path = "",
                         const std::string& detector_caffe_model_path = "",
                         const std::string& super_resolution_prototxt_path = "",
                         const std::string& super_resolution_caffe_model_path = "");
    ~WeChatQRCode(){};

    /**
     * @brief  Both detects and decodes QR code.
     * To simplify the usage, there is a only API: detectAndDecode
     *
     * @param img supports grayscale or color (BGR) image.
     * @param points optional output array of vertices of the found QR code quadrangle. Will be
     * empty if not found.
     * @return list of decoded string.
     */
    CV_WRAP std::vector<std::string> detectAndDecode(InputArray img,
                                                     OutputArrayOfArrays points = noArray());

protected:
    class Impl;
    Ptr<Impl> p;
};

从源代码上可以看出,WeChatQRCode仅仅包含一个函数: detectAndDecode,该函数返回所有二维码的位置以及二维码的内容。

三、示例代码

#include 
#include
#include

using namespace std;
using namespace cv;
using namespace cv::wechat_qrcode;

int main()
{
    Mat src = imread("D:/C++Working/image/qrImage.JPG");
    if (src.empty()) {
        cout << "could not load image" << endl;
        return -1;
    }
    imshow("src image", src);

    Ptr<WeChatQRCode> detector;
    string detect_prototxt = "./model/detect.prototxt";
    string detect_caffe_model = "./model/detect.caffemodel";
    string sr_prototxt = "./model/sr.prototxt";
    string sr_caffe_model = "./model/sr.caffemodel";

    try
    {
        detector = makePtr< WeChatQRCode>(detect_prototxt, detect_caffe_model,
            sr_prototxt, sr_caffe_model);
    }
    catch (const std::exception& e)
    {
        cout << e.what() << endl;
        return -1;
    }
    vector<Mat> vPoints;
    vector<String> strDecoded;
    strDecoded = detector->detectAndDecode(src, vPoints);

    for (int i = 0; i < strDecoded.size(); i++)
    {
        cout << "decode-" << i + 1 << ": " << strDecoded[i] << endl;
        Point pt1 = Point((int)vPoints[i].at<float>(0, 0), (int)vPoints[i].at<float>(0, 1));
        Point pt2 = Point((int)vPoints[i].at<float>(1, 0), (int)vPoints[i].at<float>(1, 1));
        Point pt3 = Point((int)vPoints[i].at<float>(2, 0), (int)vPoints[i].at<float>(2, 1));
        Point pt4 = Point((int)vPoints[i].at<float>(3, 0), (int)vPoints[i].at<float>(3, 1));
        line(src, pt1, pt2, Scalar(0, 255, 0), 2);
        line(src, pt2, pt3, Scalar(0, 255, 0), 2);
        line(src, pt3, pt4, Scalar(0, 255, 0), 2);
        line(src, pt4, pt1, Scalar(0, 255, 0), 2);
        putText(src, strDecoded[i], pt1, 0, 0.5, Scalar(255, 0, 0), 2);
    }

    imshow("result image", src);
  

    waitKey(0);
    return 0;
}


四、结果
5-QR code识别_第8张图片
五、结论
从效果上分析、该方法能够较为准确的识别二维码,但是位置精度不高(相对于ArUco)

六、注意
核心函数strDecoded = detector->detectAndDecode(img, vPoints);可以得到QRCode位置和解码内容,使用到的模型下载地址如下: https://github.com/WeChatCV/opencv_3rdparty

4-方法三

参考

你可能感兴趣的:(机器人视觉,opencv,计算机视觉,visual,studio)