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

上一个教程: Cascade 分类器训练
下一个教程: 支持向量机简介

兼容性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

相关论文: [306] , [146] , [22]

代码示例

主要类

引入了几种用于条形码识别的算法。

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

初始化

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

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

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

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

检测

cv::barcode::BarcodeDetector::detect 方法使用基于方向一致性的算法。 首先,我们计算每个像素的平均平方梯度, [22] 。 然后我们将图像分成正方形块,并计算每个块的梯度方向一致性平均梯度方向。 然后,我们连接所有具有高梯度方向一致性相似梯度方向的块。 在此阶段,我们使用多尺度块来捕获多尺寸条形码的梯度分布,并应用非最大值抑制来过滤重复的提议。 最后,我们使用 cv::minAreaRect 来边界 ROI,并输出矩形的角。

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

bardet->detectMulti(frame, corners);

解码

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

检测和解码

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

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);
}
}

结果

原始图像

image

检测之后

image