1. 程式人生 > >二維碼開源庫zbar、zxing使用心得

二維碼開源庫zbar、zxing使用心得

首先說明我的測試場景是“識別列印在紙上的二維碼”,在掃描結果中尋找二維碼並進行識別,而不是直接讓攝像頭對著二維碼掃描。

zbar和zxing用的都是自己從github上clone的c++原始碼/介面編譯出來的dll,都是預設引數

再說結論:測了大概幾千張圖片,兩個庫的準確率差不多(由於圖片場景的多樣性,確切的準確率數字也沒有什麼意義),但是zbar的速度要快很多,大概是zxing的4-5倍。其實兩個庫的準確率都不太如人意,稍微模糊一點就無法識別,甚至有一些不模糊的影象也識別不出。相比之下,微信的識別效果就逆天了,怎麼折騰都能識別出來,讓我很好奇。

後來自己嘗試改進識別效果,先看了一下二維碼的識別原理,太複雜了,無從下手。於是嘗試對影象進行預處理改進,結果只是用了一個二值化加開運算就讓識別效果得到了大幅提升,讓我很奇怪這麼簡單的預處理為什麼開發人員沒有去做呢?然後又繼續優化了一下,發現二值化的閾值對二維碼的識別非常關鍵,badcase通常是因為閾值不合適導致的,於是犧牲了一下效能,在識別程式中多次嘗試不同閾值,最終識別效果達到了比較令人滿意的結果,準確率從90%左右上升到99.8%左右,絕大部分列印不清晰導致的badcase都得到了解決,程式碼如下:

複製程式碼
#include <iostream>
#include <include\zbar.h>
#include "opencv/cv.h"
#include "opencv/highgui.h"

using namespace std;
using namespace cv;
using namespace zbar;

//zbar介面
string ZbarDecoder(Mat img)
{
    string result;
    ImageScanner scanner;
    const void *raw = (&img)->data;
    
// configure the reader scanner.set_config(ZBAR_QRCODE, ZBAR_CFG_ENABLE, 1); // wrap image data Image image(img.cols, img.rows, "Y800", raw, img.cols * img.rows); // scan the image for barcodes int n = scanner.scan(image); // extract results result = image.symbol_begin()->get_data(); image.set_data(NULL,
0); return result; } //對二值影象進行識別,如果失敗則開運算進行二次識別 string GetQRInBinImg(Mat binImg) { string result = ZbarDecoder(binImg); if(result.empty()) { Mat openImg; Mat element = getStructuringElement(MORPH_RECT, Size(3, 3)); morphologyEx(binImg, openImg, MORPH_OPEN, element); result = ZbarDecoder(openImg); } return result; } //main function string GetQR(Mat img) { Mat binImg; //在otsu二值結果的基礎上,不斷增加閾值,用於識別模糊影象 int thre = threshold(img, binImg, 0, 255, cv::THRESH_OTSU); string result; while(result.empty() && thre<255) { threshold(img, binImg, thre, 255, cv::THRESH_BINARY); result = GetQRInBinImg(binImg); thre += 20;//閾值步長設為20,步長越大,識別率越低,速度越快 } return result; }