OPENCV中对于QR code的识别有四种方法:
1、方法一:使用OPENCV模块中的QRCodeDetector(opencv版本在4以上)
2、方法二:使用OPENCV外部contrib中的wechat_qrcode外部模块(OpenCV4.5及以上)
3、方法三:根据QR code的编码原理从底层解析QR code
4、方法四:采用第三方zBar库
一、源代码
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;
}
四、结论
从检测结果上,该方法至少存在1个致命缺陷:
1、会出现漏检情况()
2、QR code存储内容太长也会出现漏检
微信开源了QRCode解码功能,OPENCV可以通过添加外部库的方法使用该模块:
一、配置方法
WeChatQRCode模块为OpenCV4.5.1新增功能,需要在github下载最新opencv源码master和contrib部分编译后使用。
源码编译使用CMake,相关编译教程很多博客写的很详细,这里只做关键步骤说明:
(1) 编译是勾选BUILD_opencv_wechat_qrcode选项(默认勾选)
(2) 勾选BUILD_opencv_world 这样只生成一个dll方便使用
(3) 先Configure,后Generate,直至不报错(警告可忽略)
(4) 打开OpenCV.Sln,先生成ALLBuild,再仅用于项目生成Install,生成成功(无错误,无失败)会得到如下文件:
接下来就是配置步骤:包含目录、库目录、附加依赖项和环境变量,这个大家用这么久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;
}
四、结果
五、结论
从效果上分析、该方法能够较为准确的识别二维码,但是位置精度不高(相对于ArUco)
六、注意
核心函数strDecoded = detector->detectAndDecode(img, vPoints);可以得到QRCode位置和解码内容,使用到的模型下载地址如下: https://github.com/WeChatCV/opencv_3rdparty
参考