36.QR二维码检测

  二维码被广泛的应用在我们日常生活中,比如微信和支付宝支付、火车票、商品标识等。二维码的出现极大的方便了我们日常的生活,同时也能将信息较为隐蔽的传输。二维码种类多种多样,有QR Code、Data Matrix、Code One等,日常生活中常用的二维码是QR二维码,该二维码样式以及每部分的作用在图7-30给出。二维码定点方向有三个较大的“回”字形区域用于对二维码进行定位,该区域最大的特别之处在于任何一条经过中心的直线其在黑色和白色区域的长度比值都为1:1:3:1:1。二维码中间具有多个较小的“回”字形区域用于二维码的对齐,根据二维码版本和尺寸的不同,对齐区域的数目也不尽相同。

  QR二维码的识别过程大致分成两个过程,首先搜索二维码的位置探测图形,即QR二维码中三个顶点处的“回”字区域,QR二维码位置以四个顶点的坐标形式给出。之后对二维码进行解码,提取其中的信息。QR二维码识别是OpenCV 4新增加的功能,OpenCV 4提供了相关函数直接解码QR二维码读取其中的信息,但是在OpenCV 4之前的版本中对QR二维码的识别需要借助第三方工具,常用的是zbar解码库。

  针对QR二维码识别的两个过程,OpenCV 4提供了多个函数用于实现每个过程,这些函数分别是定位QR二维码的detect()函数、根据定位结果解码二维码的decode()函数以及同时定位和解码的detectAndDecode()函数,接下来将详细介绍这三个函数的函数原型和使用方法。

  定位QR二维码的位置不仅可以用于解码QR二维码,也可以用于视觉定位。在利用QR二维码定位的任务中有时不需要对QR二维码进行解码,而是直接使用四个顶点的坐标,因此只定位不解码QR二维码可以加快系统的运行速度。定位QR二维码函数detect()的函数原型在代码清单7-37中给出。

代码清单7-37 detect()函数原型
bool cv::QRCodeDetector::detect(InputArray  img,
                                OutputArray  points 
                                )
  • img:待检测是否含有QR二维码的灰度图像或者彩色图像。
  • points:包含QR二维码的最小区域四边形的四个顶点坐标,即二维码的四个顶点坐标。

  该函数能够识别图像中是否含有QR二维码,以bool类型的返回值表示是否含有二维码的结果。如果图像中含有二维码,返回值为true,否则返回值为false。函数第一个参数是待检测是否含有QR二维码的图像,图像可以是灰度图像或者彩色图像,图像的尺寸任意。函数第二个参数是包含QR二维码的最小区域四边形的四个顶点坐标,数据类型为vector。

decode()函数能够利用图像中二维码的定位结果对QR二维码进行解码,该函数的函数原型在代码清单7-38中给出。

代码清单7-38 decode()函数原型
std::string cv::QRCodeDetector::decode(InputArray  img,
                                       InputArray  points,
                                       OutputArray  straight_qrcode = noArray() 
                                       )
  • img:含有QR二维码的图像。
  • points:包含QR二维码的最小区域四边形的四个顶点坐标。
  • straight_qrcode:经过校正和二值化的QR二维码。

  该函数能够根据二维码定位的结果信息对二维码进行解码,以string类型的返回值输出解码结果。该函数前两个参数与detect()函数的两个参数含义相同,不过该函数的第二个参数是输入值,数据量不能为空。函数第三个参数是经过校正和二值化的QR二维码,变量类型为Mat,在校正的二维码中每一个有效数据点都以单个像素出现,例如在经过校正和二值化的QR二维码中“回”字形区域中心的黑色区域尺寸为3×3,黑色区域边缘的白色轮廓宽度为1。

有时我们需要识别二维码中的信息,detectAndDecode()函数可以直接一步完成二维码的定位和解码过程,该函数的函数原型在代码清单7-39中给出。

代码清单7-39 detectAndDecode()函数原型
std::string cv::QRCodeDetector::detectAndDecode(InputArray  img,
                                                OutputArray  points = noArray(),
                                                OutputArray  straight_qrcode = noArray() 
                                                )
  • img:含有QR二维码的图像。
  • points:包含QR二维码的最小区域四边形的四个顶点坐标。
  • straight_qrcode:经过校正和二值化的QR二维码。

  该函数能够直接完成对QR二维码四个顶点的定位和识别图像中QR二维码的信息,并以vector类型返回四个顶点的坐标,以string类型的返回值输出QR二维码识别的结果。函数第一个参数是含有QR二维码的灰度图像或者彩色图像。第二个参数是包含QR二维码的最小区域四边形的四个顶点坐标,在此函数中该参数是输出值,如果不需要QR二维码顶点坐标可以在调用函数时缺省该参数或者使用默认参数noArray()表示不输出坐标。函数第三个参数是经过校正和二值化的QR二维码,变量类型为Mat,如果不需要输出该结果可以在调用函数时缺省该参数或者使用默认参数noArray()表示不输出图像。

代码清单7-40 mydetectQRcode.cpp二维码识别
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;

int main()
{
  Mat img = imread("qrcode2.png");
  if (img.empty())
  {
    cout << "请确认图像文件名称是否正确" << endl;
    return -1;
  }
  Mat gray, qrcode_bin;
  cvtColor(img, gray, COLOR_BGR2GRAY);
  QRCodeDetector qrcodedetector;
  vector<Point> points;
  string information;
  bool isQRcode;
  isQRcode = qrcodedetector.detect(gray, points);  //识别二维码
  if (isQRcode)
  {
    //解码二维码
    information = qrcodedetector.decode(gray, points, qrcode_bin);
    cout << points << endl;  //输出二维码四个顶点的坐标
  }
  else
  {
    cout << "无法识别二维码,请确认图像时候含有二维码" << endl;
    return -1;
  }
  //绘制二维码的边框
  for (int i = 0; i < points.size(); i++)
  {
    if (i == points.size() - 1)
    {
      line(img, points[i], points[0], Scalar(0, 0, 255), 2, 8);
      break;
    }
    line(img, points[i], points[i + 1], Scalar(0, 0, 255), 2, 8);
  }
  //将解码内容输出到图片上
  putText(img, information.c_str(), Point(20, 30), 0, 1.0, Scalar(0, 0, 255), 2, 8);

  //利用函数直接定位二维码并解码
  string information2;
  vector<Point> points2;
  information2 = qrcodedetector.detectAndDecode(gray, points2);
  cout << points2 << endl;
  putText(img, information2.c_str(), Point(20, 55), 0, 1.0, Scalar(0, 0, 0), 2, 8);

  //输出结果
  imshow("result", img);
  namedWindow("qrcode_bin", WINDOW_NORMAL);
  imshow("qrcode_bin", qrcode_bin);
  waitKey(0);
  return 0;
}

 

posted @ 2023-04-11 16:58  夏蝉沐雪  阅读(202)  评论(0编辑  收藏  举报