一、二维码检测
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();