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> contours;
	vector 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;
}

代码是结构化的,检测和识别的代码网上都有相关的例程,结合后加入了些自己的东西。动态扫描目标图像并传递,效率更高些。运行效果如图:

opencv+zbar二维码检测及扫描_第1张图片opencv+zbar二维码检测及扫描_第2张图片opencv+zbar二维码检测及扫描_第3张图片opencv+zbar二维码检测及扫描_第4张图片

你可能感兴趣的:(opencv+zbar二维码检测及扫描)