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