opencv3+Zbar识别二维码--水平垂直交叉定位

http://blog.csdn.net/dcrmg/article/details/52132313

成像比较清晰,二维码占据整个图像的比例达到4成以上的标准二维码,用opencv和zbar识别还是很容易的,而且zbar的鲁棒性很好。

// Zbar_code.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<iostream>
#include<zbar.h>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\opencv.hpp>

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

Rect DrawXY(const Mat image, Mat &imageOut, const int threshodValue, const int binaryzationValue);

int main()
{
	// 定义Zbar扫描的类
	ImageScanner scanner;
	// 初始化
	scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
	// 加载二维码图像数据
	Mat srcImage = imread("baidu.jpg");
	if (!srcImage.data) {
		cout << "Input image error!" << endl;
		system("pause");
		return 0;
	}
	Mat src_copy = srcImage.clone();
	Mat src_gray, dstImage;
	cvtColor(srcImage, src_gray, CV_BGR2GRAY);

	int width = src_gray.cols;
	int height = src_gray.rows;
	// wrap the image
	uchar*raw = (uchar*)src_gray.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;
		cout << "条码:" << endl << symbol->get_data() << endl;
	}

	imshow("原始二维码图片", srcImage);

	Rect rect(0, 0, 0, 0);
	// 调用函数将二维码区域截取
	rect = DrawXY(srcImage, dstImage, srcImage.rows / 10, 150);
	Mat roi = srcImage(rect);
	// 根据获取的二维码矩形区域四个角点坐标在原图像上画出二维码
	rectangle(src_copy, Point(rect.x, rect.y), Point(rect.x + rect.width, rect.y + rect.height), Scalar(0, 0, 255), 4);
	imshow("水平垂直投影", dstImage);
	imshow("截取的二维码区域", roi);
	imshow("圈画原始图像二维码区域", src_copy);

	waitKey(0);
	imageZbar.set_data(NULL, 0);

    return 0;
}

//***********************************************  
// 函数通过水平和垂直方向投影,找到两个方向上投影的交叉矩形,定位到条形码/二维码  
// int threshodValue 投影的最少像素单位  
// int binaryzationValue  原图像阈值分割值  
//***********************************************

Rect DrawXY(const Mat image, Mat &imageOut, const int threshodValue, const int binaryzationValue)
{
	// 将原始图像备份
	Mat img = image.clone();
	// 非单通道图像先预处理--灰度化
	if (img.channels()>1)
	{
		cvtColor(img, img, CV_RGB2GRAY);
	}
	// 根据原始图像的尺寸构建新的图像用于接收投影信息
	Mat out(img.size(), img.type(), Scalar(255));
	imageOut = out;
	// 对每一个传入的图片做灰度归一化,以便使用同一套阈值参数
	normalize(img, img, 0, 255, NORM_MINMAX);
	// 垂直方向投影,构建数组向量,包含img.cols维度
	vector<int> vectorVertical(img.cols, 0);
	// 根据像素坐标所在像素值大小与阈值比较,若有黑店覆盖则计数+1
	for (int i = 0; i<img.cols; i++)
	{
		for (int j = 0; j<img.rows; j++)
		{
			if (img.at<uchar>(j, i)<binaryzationValue)
			{
				vectorVertical[i]++;
			}
		}
	}
	// 列值归一化  
	int high = img.rows / 6;
	normalize(vectorVertical, vectorVertical, 0, high, NORM_MINMAX);
	for (int i = 0; i<img.cols; i++)
	{
		for (int j = 0; j<img.rows; j++)
		{
			// 少于设置的像素统计值则不显示柱状图,这里srcImage.rows / 10根据二维码的定位区域得到
			// 还需要研究,后期会更新这参数计算原理
			if (vectorVertical[i]>threshodValue)
			{
				line(imageOut, Point(i, img.rows), Point(i, img.rows - vectorVertical[i]), Scalar(0, 0, 0));
			}
		}
	}
	//水平投影  
	vector<int> vectorHorizontal(img.rows, 0);
	for (int i = 0; i<img.rows; i++)
	{
		for (int j = 0; j<img.cols; j++)
		{
			if (img.at<uchar>(i, j)<binaryzationValue)
			{
				vectorHorizontal[i]++;
			}
		}
	}
	normalize(vectorHorizontal, vectorHorizontal, 0, high, NORM_MINMAX);
	for (int i = 0; i<img.rows; i++)
	{
		for (int j = 0; j<img.cols; j++)
		{
			if (vectorHorizontal[i]>threshodValue)
			{
				line(imageOut, Point(img.cols - vectorHorizontal[i], i), Point(img.cols, i), Scalar(0));
			}
		}
	}
	//找到投影四个角点坐标  
	vector<int>::iterator beginV = vectorVertical.begin();
	vector<int>::iterator beginH = vectorHorizontal.begin();
	vector<int>::iterator endV = vectorVertical.end() - 1;
	vector<int>::iterator endH = vectorHorizontal.end() - 1;
	int widthV = 0;
	int widthH = 0;
	int highV = 0;
	int highH = 0;
	while (*beginV<threshodValue)
	{
		beginV++;
		widthV++;
	}
	while (*endV<threshodValue)
	{
		endV--;
		widthH++;
	}
	while (*beginH<threshodValue)
	{
		beginH++;
		highV++;
	}
	while (*endH<threshodValue)
	{
		endH--;
		highH++;
	}
	//投影矩形  
	Rect rect(widthV, highV, img.cols - widthH - widthV, img.rows - highH - highV);
	return rect;
}

二维码:







条形码:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值