OpenCV 4.11.0
开源计算机视觉库
加载中…
搜索中…
无匹配项
条形码识别

上一篇教程: 级联分类器训练
下一篇教程: 支持向量机简介

兼容性OpenCV >= 4.8

目标

本章我们将学习OpenCV中可用的条形码检测和解码方法。

基础知识

条形码是现实生活中识别商品的主要技术。常见的条形码是由黑色条和白色条组成的平行线图案,其反射率差异很大。条形码识别是沿水平方向扫描条形码,以获得由不同宽度和颜色的条组成的二进制代码串,即条形码的代码信息。条形码的内容可以通过与各种条形码编码方法匹配来解码。目前,我们支持EAN-8、EAN-13、UPC-A和UPC-E标准。

参见 https://en.wikipedia.org/wiki/Universal_Product_Codehttps://en.wikipedia.org/wiki/International_Article_Number

相关论文: [304] , [143] , [21]

代码示例

主类

已经引入了几种条形码识别算法。

编码时,首先需要创建一个 cv::barcode::BarcodeDetector 对象。它主要有三个成员函数,将在下面介绍。

初始化

用户可以选择使用超分辨率模型构造条形码检测器,该模型应从 https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode (sr.caffemodel, sr.prototxt) 下载。

尝试
{
app.bardet = makePtr<barcode::BarcodeDetector>(sr_prototxt, sr_model);
}
catch (const std::exception& e)
{
cout <<
"\n---------------------------------------------------------------\n"
"未能初始化超分辨率。\n"
"请从以下地址下载 'sr.*':\n"
"https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode\n"
"并将它们放入当前目录。\n"
"或者您可以不指定 sr_prototxt 和 sr_model。\n"
"---------------------------------------------------------------\n";
cout << e.what() << endl;
返回 -1;
}

我们需要创建变量来存储输出。

vector<Point> corners;
vector<string> decode_info;
vector<string> decode_type;

检测

cv::barcode::BarcodeDetector::detect 方法使用基于方向一致性的算法。首先,我们计算每个像素的平均平方梯度, [21] 。然后我们将图像划分为方形块,并计算每个块的**梯度方向一致性**和**平均梯度方向**。然后,我们将所有具有**高梯度方向一致性**和**相似梯度方向**的块连接起来。在这个阶段,我们使用多尺度块来捕捉多尺寸条形码的梯度分布,并应用非最大抑制来过滤重复的建议。最后,我们使用 cv::minAreaRect 来绑定 ROI,并输出矩形的角点。

检测输入图像中的代码,并输出检测到的矩形的角点

bardet->detectMulti(frame, corners);

解码

cv::barcode::BarcodeDetector::decode 方法首先(可选)对小于阈值的图像进行超比例缩放,锐化图像,然后通过 OTSU 或局部二值化对其进行二值化。然后,它通过匹配指定条形码图案的相似性来读取条形码的内容。

检测和解码

cv::barcode::BarcodeDetector::detectAndDecodedetectdecode组合在一个调用中。下面的一个简单示例展示了如何使用此函数

bardet->detectAndDecodeWithType(frame, decode_info, decode_type, corners);

可视化结果

for (size_t i = 0; i < corners.size(); i += 4)
{
const size_t idx = i / 4;
const bool isDecodable = idx < decode_info.size()
&& idx < decode_type.size()
&& !decode_type[idx].empty();
const Scalar lineColor = isDecodable ? greenColor : redColor;
// 绘制条形码矩形
vector<Point> contour(corners.begin() + i, corners.begin() + i + 4);
const vector< vector<Point> > contours {contour};
drawContours(frame, contours, 0, lineColor, 1);
// 绘制顶点
for (size_t j = 0; j < 4; j++)
circle(frame, contour[j], 2, randColor(), -1);
// 写入解码文本
if (isDecodable)
{
ostringstream buf;
buf << "[" << decode_type[idx] << "] " << decode_info[idx];
putText(frame, buf.str(), contour[1], FONT_HERSHEY_COMPLEX, 0.8, yellowColor, 1);
}
}

结果

原始图像

图像

检测后

图像