OpenCV联合C++/Qt 学习笔记(十八)----二维码检测及积分图像

一、二维码检测

1、QR二维码识别原理

定位图案:用于快速定位二维码位置

对齐图案: 矫正透视变形

时序图案:确定网格坐标

格式信息: 保存纠错等级等信息

数据区域:真正存储数据

纠错码: 用于损坏恢复

2、二维码定位与识别的相关函数

2.1.1 二维码定位函数
cpp 复制代码
/* 用途:用于检测图像中是否存在二维码(QR Code),
       并定位二维码在图像中的位置 */
bool cv::QRCodeDetector::detect(InputArray img, OutputArray points) const;
/*
img:待检测是否含有QR码的灰度图像或者彩色图像
points:包含QR码的最小区域四边形的四个顶点坐标,即二维码的四个顶点坐标
*/
2.1.2 二维码识别函数
cpp 复制代码
/* 用途:用于对已经定位好的二维码进行解码,
       根据二维码区域的四个顶点坐标,
       自动完成二维码区域提取、透视校正以及内容解析,
       最终获得二维码中的字符串信息 */
std::string cv::QRCodeDetector::decode(InputArray img, InputArray points, 
                                    OutputArray straight_qrcode = noArray());
/*
img:含有QR码的图像
points:包含QR码的最小区域四边形的四个顶点坐标
straight_qrcode:经过矫正和二值化的QR码
*/
2.1.3 直接定位与识别函数
cpp 复制代码
/* 用途:用于一步完成二维码的检测、定位和解码操作 */
std::string cv::QRCodeDetector::detectAndDecode(InputArray img, 
                                        OutputArray points=noArray(),
                                        OutputArray straight_qrcode = noArray());
/*
img:含有QR码的图像
points:包含QR码的最小区域四边形的四个顶点坐标
straight_qrcode:经过校正和二值化的QR码
*/
2.1.4 示例代码
cpp 复制代码
    QString imgPath = QApplication::applicationDirPath() + "/Images";
    cv::String s_imgPath = imgPath.toLocal8Bit().data();
    Mat img = imread(s_imgPath + "/qrcode.png");
    if (img.empty())
    {
        qDebug() << "图片加载失败, 请确认图像文件名称是否正确";
        return;
    }

    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 << "NO Read QR Code" << endl;
        return;
    }
    /*绘制二维码的边框*/
    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, 50), 0, 1.0, Scalar(0, 0, 0), 2, 8);


    imshow("img", img);
    namedWindow("qrcode_bin", WINDOW_NORMAL);
    imshow("qrcode_bin", qrcode_bin);

    waitKey(0);
    destroyAllWindows();

二、积分图像

1、积分图像介绍

积分图像顾名思义,就是求和,完整的意思是每一个像素点的灰度值等于在该像素点之前所有像素点灰度值之和。

深色区域的灰度值之和就是:120-42-21+6=63

计算原理如下:

上图为一张原始图像,其标示了四个区域:A, B , C ,D

1 处像素点对应的在积分图像中的值为:sum(A);

2 处像素点对应的在积分图像中的值为:sum(A+B);

3 处像素点对应的在积分图像中的值为:sum(A+C);

4 处像素点对应的在积分图像中的值为:sum(A+B+C+D);

则:

区域D所有的像素点灰度值之和为:

sum(A+B+C+D) - sum(A+C) - sum(A+B) + sum(A)

2、相关函数

cpp 复制代码
/* 用途:用于计算图像的积分图像,
       通过预先统计像素累加和,
       可以快速计算任意矩形区域内的像素和 */
void cv::integral( InputArray src, OutputArray sum,
                                        OutputArray sqsum, OutputArray tilted,
                                        int sdepth = -1, int sqdepth = -1 );
/*
src:输入图像,图像数据类型可以是CV_8U、CV_32F或者CV_64
sum:输出标准求和积分图像,图像的数据类型可以是CV_8U、CV_32F或者CV_64
sqsum:输出平方求和积分图像,图像的数据类型可以是CV_8U、CV_32F或者CV_64
tilted:输出倾斜45°的倾斜求和积分图像,其数据类型与sum相同
sdepth:输出标准求和积分图像和倾斜求和积分图像的数据类型标志,可以选择的参数为CV_32S、
        CV_32F或者CV_64F,参数默认值为-1,表示满足数据存储的自适应类型
sqdepth:输出平方求和积分图像的数据类型标志,可以选择的参数为CV_32F或者CV_64F,参数默认
        值为-1,表示满足数据存储的自适应类型
*/

3、示例代码

cpp 复制代码
    /*创建一个16 x 16 全为1的矩阵,因为256 = 16 x 16*/
    Mat img = Mat::ones(16, 16, CV_32FC1);

    /*在图像中加入随机噪声*/
    RNG rng(10086);
    for (int y = 0; y < img.rows; y++)
    {
        for (int x = 0; x < img.cols; x++)
        {
            float d = rng.uniform(-0.5, 0.5);
            img.at<float>(y, x) = img.at<float>(y, x) + d;
        }
    }
    /*计算标准求和积分*/
    Mat sum;
    integral(img, sum);
    /*为了便于显示,转成CV_8U格式*/
    Mat sum8U = Mat_<uchar>(sum);
    namedWindow("sum8U", WINDOW_NORMAL);
    imshow("sum8U", sum8U);

    /*计算平方求和积分*/
    Mat sqsum;
    integral(img, sum,sqsum);
    /*为了便于显示,转成CV_8U格式*/
    Mat sqsum8U = Mat_<uchar>(sqsum);
    namedWindow("sqsum8U", WINDOW_NORMAL);
    imshow("sqsum8U", sqsum8U);

    /*计算倾斜求和积分*/
    Mat tilted;
    integral(img, sum, sqsum, tilted);
    /*为了便于显示,转成CV_8U格式*/
    Mat tilted8U = Mat_<uchar>(tilted);
    namedWindow("tilted8U", WINDOW_NORMAL);
    imshow("tilted8U", tilted8U);

    waitKey(0);
    destroyAllWindows();
相关推荐
AOwhisky17 分钟前
Ceph系列第六期:Ceph 文件系统(CephFS)精讲
linux·运维·网络·笔记·ceph
萤萤七悬21 分钟前
【Python笔记】AI帮实现CLI工具-使用argparse.ArgumentParser接收命令参数
开发语言·笔记·python
王老师青少年编程35 分钟前
信奥赛C++提高组csp-s之搜索进阶(搜索剪枝核心思想 )
c++·dfs·csp·信奥赛·搜索剪枝·搜索优化
一拳一个呆瓜35 分钟前
【STL】使用 C++ 标准库标头
c++·stl
Starry-sky(jing)1 小时前
# Linux 下 Qt 应用无障碍自动化:记一次wx无人值守系统的架构演进
linux·qt·自动化
小智老师PMP1 小时前
零基础能不能考PMP?零基础专属学习路径+全套扶持体系
学习·算法·职场和发展·软件工程·求职招聘·敏捷流程
王老师青少年编程1 小时前
信奥赛C++提高组csp-s之搜索进阶(搜索剪枝案例实践2)
c++·信奥赛·csp-s·提高组·搜索剪枝·生日蛋糕·最优性剪枝
c++之路1 小时前
C++ 设计模式全总结
java·c++·设计模式
c238562 小时前
c/c++中的多态(上)
开发语言·c++
彷徨而立2 小时前
【C++】介绍 std::ifstream 输入文件流
开发语言·c++