Opencv+Zbar二维码识别(标准条形码/二维码识别)
来源:互联网 发布:淘客基地源码 编辑:程序博客网 时间:2024/05/16 09:28
使用OpenCV+Zbar组合可以很容易的识别图片中的二维码,特别是标准的二维码,这里标准指的是二维码成像清晰,图片中二维码的空间占比在40%~100%之间,这样标准的图片,Zbar识别起来很容易,不需要opencv额外的处理。
下边这个例程演示两者配合对条形码和二维码的识别:
- #include “zbar.h”
- #include “cv.h”
- #include “highgui.h”
- #include <iostream>
- using namespace std;
- using namespace zbar; //添加zbar名称空间
- using namespace cv;
- int main(int argc,char*argv[])
- {
- ImageScanner scanner;
- scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
- Mat image = imread(argv[1]);
- Mat imageGray;
- cvtColor(image,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”,image);
- waitKey();
- imageZbar.set_data(NULL,0);
- return 0;
- }
#include "zbar.h"
二维码:
这样“标准的”二维码是Zbar非常拿手的,能准确快速的检测出来,包括在条形码外有部分其他信息的,也是小菜一碟:
Zbar很省心,我们还是可以为它做点什么的,比如在一些情况下,需要把条形码裁剪出来,这就涉及到条形码位置的定位,这篇文章准备记录一下如何定位条形码,在定位之后再把裁剪出来的条形码区域丢给Zbar识别读码。
方法一. 水平、垂直方向投影
- #include “zbar.h”
- #include “cv.h”
- #include “highgui.h”
- #include <iostream>
- using namespace std;
- using namespace zbar; //添加zbar名称空间
- using namespace cv;
- //***********************************************
- // 函数通过水平和垂直方向投影,找到两个方向上投影的交叉矩形,定位到条形码/二维码
- // int threshodValue 投影的最少像素单位
- // int binaryzationValue 原图像阈值分割值
- //***********************************************
- Rect DrawXYProjection(const Mat image,Mat &imageOut,const int threshodValue,const int binaryzationValue);
- int main(int argc,char*argv[])
- {
- Mat image = imread(argv[1]);
- Mat imageCopy=image.clone();
- Mat imageGray,imagOut;
- cvtColor(image,imageGray,CV_RGB2GRAY);
- Rect rect(0,0,0,0);
- rect= DrawXYProjection(image,imagOut,image.rows/10,100);
- Mat roi=image(rect);
- //画出条形码的矩形框
- rectangle(imageCopy,Point(rect.x,rect.y),Point(rect.x+rect.width,rect.y+rect.height),Scalar(0,0,255),2);
- imshow(”Source Image”,image);
- imshow(”水平垂直投影”,imagOut);
- imshow(”Output Image”,roi);
- imshow(”Source Image Rect”,imageCopy);
- waitKey();
- return 0;
- }
- Rect DrawXYProjection(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);
- vector<int> vectorVertical(img.cols,0);
- 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++)
- {
- if(vectorVertical[i]>threshodValue)
- {
- line(imageOut,Point(i,img.rows),Point(i,img.rows-vectorVertical[i]),Scalar(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;
- }
#include "zbar.h"#include "cv.h" #include "highgui.h" #include <iostream> using namespace std; using namespace zbar; //添加zbar名称空间 using namespace cv; //***********************************************// 函数通过水平和垂直方向投影,找到两个方向上投影的交叉矩形,定位到条形码/二维码// int threshodValue 投影的最少像素单位// int binaryzationValue 原图像阈值分割值//***********************************************Rect DrawXYProjection(const Mat image,Mat &imageOut,const int threshodValue,const int binaryzationValue);int main(int argc,char*argv[]) { Mat image = imread(argv[1]); Mat imageCopy=image.clone(); Mat imageGray,imagOut; cvtColor(image,imageGray,CV_RGB2GRAY); Rect rect(0,0,0,0); rect= DrawXYProjection(image,imagOut,image.rows/10,100); Mat roi=image(rect); //画出条形码的矩形框 rectangle(imageCopy,Point(rect.x,rect.y),Point(rect.x+rect.width,rect.y+rect.height),Scalar(0,0,255),2); imshow("Source Image",image); imshow("水平垂直投影",imagOut); imshow("Output Image",roi); imshow("Source Image Rect",imageCopy); waitKey(); return 0;} Rect DrawXYProjection(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); vector<int> vectorVertical(img.cols,0); 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++) { if(vectorVertical[i]>threshodValue) { line(imageOut,Point(i,img.rows),Point(i,img.rows-vectorVertical[i]),Scalar(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;}
通过图像在水平和垂直方向上的投影,按照一定的阈值,找到二维码所在位置,剪切出来用于下一步Zbar条码识别。当然这个方法只能识别出背景简单的图片中的二维码。
条形码效果:
水平、垂直投影
检出条形码区域
二维码效果:
方法二.梯度运算
- #include “core/core.hpp”
- #include “highgui/highgui.hpp”
- #include “imgproc/imgproc.hpp”
- using namespace cv;
- int main(int argc,char *argv[])
- {
- Mat image,imageGray,imageGuussian;
- Mat imageSobelX,imageSobelY,imageSobelOut;
- image=imread(argv[1]);
- //1. 原图像大小调整,提高运算效率
- resize(image,image,Size(500,300));
- imshow(”1.原图像”,image);
- //2. 转化为灰度图
- cvtColor(image,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_NONE);
- for(int i=0;i<contours.size();i++)
- {
- Rect rect=boundingRect((Mat)contours[i]);
- rectangle(image,rect,Scalar(255),2);
- }
- imshow(”10.找出二维码矩形区域”,image);
- waitKey();
- }
#include "core/core.hpp"#include "highgui/highgui.hpp" #include "imgproc/imgproc.hpp" using namespace cv; int main(int argc,char *argv[]) { Mat image,imageGray,imageGuussian; Mat imageSobelX,imageSobelY,imageSobelOut; image=imread(argv[1]); //1. 原图像大小调整,提高运算效率 resize(image,image,Size(500,300)); imshow("1.原图像",image); //2. 转化为灰度图 cvtColor(image,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_NONE); for(int i=0;i<contours.size();i++) { Rect rect=boundingRect((Mat)contours[i]); rectangle(image,rect,Scalar(255),2); } imshow("10.找出二维码矩形区域",image); waitKey(); }
原图像
平滑滤波
水平和垂直方向灰度图像的梯度差
闭运算、腐蚀、膨胀后通过findContours找到条形码区域的矩形边界
二维码:
原图:
平衡滤波
梯度和
闭运算、腐蚀、膨胀后通过findContours找到条形码区域的矩形边界
阅读全文
0 0
- Opencv+Zbar二维码识别(标准条形码/二维码识别)
- Opencv+Zbar二维码识别(标准条形码/二维码识别)
- Opencv+Zbar二维码识别(标准条形码/二维码识别)
- Opencv+Zbar二维码识别(标准条形码/二维码识别)
- Opencv+Zbar二维码识别(标准条形码/二维码识别)
- Opencv+Zbar二维码识别(二维码校正)
- Opencv+Zbar二维码识别(二维码校正)
- Opencv+Zbar二维码识别(二维码校正)
- Opencv+Zbar二维码识别(二维码校正)
- Opencv+Zbar二维码识别(一维码校正)
- Opencv+Zbar二维码识别(一维码校正)
- c++ zbar opencv 二维码识别
- ZBar进行二维码识别
- Qt和Zbar的结合使用识别二维码条形码
- Zbar和ZXing这两个二维码和条形码识别工具
- Ros下跑opencv zbar 识别二维码Qr
- opencv+zbar在arm下二维码识别检测
- opencv二维码识别解码
- jdbc的增删改查
- 二维码解码器Zbar+VS2012开发环境配置
- nrf51822的ibeacon调试心得
- jquery实现返回顶部按钮和scroll滚动功能[带动画效果]
- 二叉树深度问题
- Opencv+Zbar二维码识别(标准条形码/二维码识别)
- JAVA-26.1-jQuery基础、派发事件、效果、选择器
- "你遇到过哪些高质量的C++面试?"
- Opencv+Zbar二维码识别(二维码校正)
- 数据库中的各种键
- 企业网站需要多大空间
- NPC(NP完全问题)证明
- Workerman WebSocket示例
- 字典