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

来源:互联网 发布:下载淘宝网商城 编辑:程序博客网 时间:2024/06/08 18:33

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 imageuchar*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);// 根据像素坐标所在像素值大小与阈值比较,若有黑店覆盖则计数+1for (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;}

二维码:







条形码:


原创粉丝点击