1. 程式人生 > >opencv+zbar二維碼檢測及掃描

opencv+zbar二維碼檢測及掃描

通過子函式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;
}

程式碼是結構化的,檢測和識別的程式碼網上都有相關的例程,結合後加入了些自己的東西。動態掃描目標影象並傳遞,效率更高些。執行效果如圖: