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();
相关推荐
SwJieJie2 小时前
Day1 从 0 搭建 VueDemo Web Admin 项目环境:技术栈、插件链与自动化脚本全解析
前端·vue.js·学习
JAVA面经实录9172 小时前
Java核心底层原理全集(终版无遗漏·生产级PDF)
java·开发语言·学习
Rabitebla2 小时前
深入理解 C++ STL:stack 和 queue 的底层原理与实现
c语言·开发语言·数据结构·c++·算法
其实防守也摸鱼2 小时前
upload-labs靶场的pass-2~12的解题步骤及原理讲解
笔记·安全·web安全·网络安全·教程·web·工具
GISer_Jing2 小时前
GIS论述-6大核心技术方向全解II
学习·考研·arcgis
DataBuildWorld2 小时前
Claude Code 从入门到精通
学习
nashane2 小时前
HarmonyOS 6学习:超大分辨率图片压缩与长截图生成优化实践
学习·华为·harmonyos
谙弆悕博士2 小时前
R 语言学习笔记
笔记·学习·数据分析·r语言·数据可视化
不灭锦鲤2 小时前
网络安全学习第108天
学习