opencv+zbar二維碼檢測及掃描
阿新 • • 發佈:2018-12-31
通過子函式zbar_find()檢測圖片中二維碼的位置並用矩形框標出
通過zbar_detect()函式呼叫zbar庫對Roi進行掃描,並輸出掃描結果
因為圖片中二維碼數目多,且二維碼分佈有一定規律(均在圖片下部,類似於書櫃中書籍排列),所以採用擷取圖片中roi傳遞給子函式進行檢測掃描的方式。
程式碼如下:
#include "core/core.hpp" #include "zbar.h" #include "highgui/highgui.hpp" #include "imgproc/imgproc.hpp" #include "iostream" #include "string.h" #define h 800 #define w 1000 using namespace cv; using namespace zbar; using namespace std; void zbar_find(Mat img); string zbar_detect(Mat bar); float area; Rect rect; int main() { Mat img = imread("C:\\Users\\Administrator\\Desktop\\zbar4.jpg"); resize(img, img, Size(w, h)); //原影象大小調整,提高運算效率 namedWindow("1",0); imshow("1", img); float d=0; float t = 155; //ROI區域的寬度 float h1 = h / 3 * 2; //擷取圖片下1/3段 float h2 = h / 3; //roi高度 Mat roi; for (d = 0; d < w-t;d+=50) //d位移掃描圖片 { Mat img1 = img.clone(); //重新整理原圖 避免ROI出現多次 roi = img1(Rect(d,h1, t, h2)); //定義roi尺寸 zbar_find(roi); //查詢roi區域 string data=zbar_detect(roi); //識別roi中條形碼 string data1; if (string(data1)!=string(data)) { data1 = data; cout << "條碼:" << endl << data1 << endl; } waitKey(500); } printf("%d,%d", h, w); waitKey(0); } void zbar_find(Mat img) { Mat image,imageGray, imageGuussian; Mat imageSobelX, imageSobelY, imageSobelOut; //2. 轉化為灰度圖 cvtColor(img, imageGray, CV_RGB2GRAY); /*imshow("2.灰度圖", imageGray);*/ //3. 高斯平滑濾波 GaussianBlur(imageGray, imageGuussian, Size(3, 3), 0); /*imshow("3.高斯平衡濾波", imageGuussian);*/ //4.求得水平和垂直方向灰度影象的梯度和,使用Sobel運算元 Mat imageX16S, imageY16S; Sobel(imageGuussian, imageX16S, CV_16S, 1, 0, 3, 1, 0, 4); Sobel(imageGuussian, imageY16S, CV_16S, 0, 1, 3, 1, 0, 4); convertScaleAbs(imageX16S, imageSobelX, 1, 0); convertScaleAbs(imageY16S, imageSobelY, 1, 0); imageSobelOut = imageSobelX + imageSobelY; /*imshow("4.X方向梯度", imageSobelX); imshow("4.Y方向梯度", imageSobelY); imshow("4.XY方向梯度和", imageSobelOut); */ //5.均值濾波,消除高頻噪聲 blur(imageSobelOut, imageSobelOut, Size(3, 3)); /*imshow("5.均值濾波", imageSobelOut);*/ //6.二值化 Mat imageSobleOutThreshold; threshold(imageSobelOut, imageSobleOutThreshold, 180, 255, CV_THRESH_BINARY); /*imshow("6.二值化", imageSobleOutThreshold);*/ //7.閉運算,填充條形碼間隙 Mat element = getStructuringElement(0, Size(7, 7)); morphologyEx(imageSobleOutThreshold, imageSobleOutThreshold, MORPH_CLOSE, element); /*imshow("7.閉運算", imageSobleOutThreshold);*/ //8. 腐蝕,去除孤立的點 erode(imageSobleOutThreshold, imageSobleOutThreshold, element); /*imshow("8.腐蝕", imageSobleOutThreshold);*/ /*/9. 膨脹,填充條形碼間空隙,根據核的大小,有可能需要2~3次膨脹操作 */ dilate(imageSobleOutThreshold, imageSobleOutThreshold, element); dilate(imageSobleOutThreshold, imageSobleOutThreshold, element); dilate(imageSobleOutThreshold, imageSobleOutThreshold, element); /*imshow("9.膨脹", imageSobleOutThreshold);*/ vector<vector<Point>> contours; vector<Vec4i> hiera; //10.通過findContours找到條形碼區域的矩形邊界 findContours(imageSobleOutThreshold, contours, hiera, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); for (int i = 0; i<(contours.size()-1); i++) { if (contourArea(contours[i])>contourArea(contours[i+1])) rect = boundingRect((Mat)contours[i]); else rect = boundingRect((Mat)contours[i+1]); } rectangle(img, rect, Scalar(255), 2); namedWindow("找出二維碼矩形區域"); imshow("找出二維碼矩形區域", img); waitKey(5); } string zbar_detect(Mat bar) { ImageScanner scanner; scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1); Mat imageGray; cvtColor(bar, imageGray, CV_RGB2GRAY); int width = imageGray.cols; int height = imageGray.rows; uchar *raw = (uchar *)imageGray.data; Image imageZbar(width, height, "Y800", raw, width * height); scanner.scan(imageZbar); //掃描條碼 Image::SymbolIterator symbol = imageZbar.symbol_begin(); /*if (imageZbar.symbol_begin() == imageZbar.symbol_end()) { cout << "查詢條碼失敗,請檢查圖片!" << endl; }*/ for (; symbol != imageZbar.symbol_end(); ++symbol) { cout << "型別:" << endl << symbol->get_type_name() << endl << endl; cout << "條碼:" << endl << symbol->get_data() << endl << endl; } /*imshow("Source Image", bar); waitKey();*/ string data = symbol->get_data(); imageZbar.set_data(NULL, 0); return data; }
程式碼是結構化的,檢測和識別的程式碼網上都有相關的例程,結合後加入了些自己的東西。動態掃描目標影象並傳遞,效率更高些。執行效果如圖: