Opencv+Zbar二维码识别(标准条形码/二维码识别)
使用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;
}
条形码:
二维码:
这样“标准的”二维码是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;
}
通过图像在水平和垂直方向上的投影,按照一定的阈值,找到二维码所在位置,剪切出来用于下一步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();
}
原图像
平滑滤波
水平和垂直方向灰度图像的梯度差
闭运算、腐蚀、膨胀后通过findContours找到条形码区域的矩形边界
二维码:
原图:
平衡滤波
梯度和
闭运算、腐蚀、膨胀后通过findContours找到条形码区域的矩形边界
Opencv+Zbar二维码识别(标准条形码/二维码识别)的更多相关文章
- iOS开发——iOS7(及以后版本) SDK自带二维码(含条形码)扫码、二维码生成
本文转载至 http://www.cnblogs.com/leotangcn/p/4357907.html 现在很多APP都涉及了二维码扫码功能,这个功能简单实用,很多情况下用户乐于使用,现在本文带来 ...
- Opencv+Zbar二维码识别(二维码校正)
二维码和车牌识别基本都会涉及到图像的校正,主要是形变和倾斜角度的校正,一种二维码的畸变如下图: 这个码用微信扫了一下,识别不出来,但是用Zbar还是可以准确识别的~~. 这里介绍一种二维码校正方法,通 ...
- ZBar 是款桌面电脑用条形码/二维码扫描工具
ZBar 是款桌面电脑用条形码/二维码扫描工具 windows平台python 2.7环境编译安装zbar 最近一个项目需要识别二维码,找来找去找到了zbar和zxing,中间越过无数坑,总算基本 ...
- QRCode 扫描二维码、扫描条形码、相册获取图片后识别、生成带 Logo 二维码、支持微博微信 QQ 二维码扫描样式
目录 功能介绍 常见问题 效果图与示例 apk Gradle 依赖 布局文件 自定义属性说明 接口说明 关于我 功能介绍 根据之前公司的产品需求,参考 barcodescanner 改的,希望能帮助到 ...
- 基于Opencv识别,矫正二维码(C++)
参考链接 [ 基于opencv 识别.定位二维码 (c++版) ](https://www.cnblogs.com/yuanchenhui/p/opencv_qr.html) OpenCV4.0.0二 ...
- 在Android上使用ZXing识别条形码/二维码
越来越多的手机具备自动对焦的拍摄功能,这也意味着这些手机可以具备条码扫描的功能.......手机具备条码扫描的功能,可以优化购物流程,快速存储电子名片(二维码)等. 本文使用ZXing 1.6实现条码 ...
- 基于opencv 识别、定位二维码 (c++版)
前言 因工作需要,需要定位图片中的二维码:我遂查阅了相关资料,也学习了opencv开源库.通过一番努力,终于很好的实现了二维码定位.本文将讲解如何使用opencv定位二维码. 定位二维码不仅仅是为了识 ...
- Java 条形码 二维码 的生成与解析
Barcode简介 Barcode是由一组按一定编码规则排列的条,空符号,用以表示一定的字符,数字及符号组成的,一种机器可读的数据表示方式. Barcode的形式多种多样,按照它们的外观分类: Lin ...
- C# 生成二维码,彩色二维码,带有Logo的二维码及普通条形码
每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默.我眼中的程序员大多都不 ...
随机推荐
- float类型的使用
将身高字段设置为float类型,保留一位小数: ALTER TABLE `user` CHANGE `height` `height` FLOAT(4,1) UNSIGNED NOT NULL DEF ...
- POSTMAN编写文档
第一步:创建文件夹: 同时创建全局变量: 第二步:创建分组文件夹: 第三步:添加请求: 类似正常调试,然后多了一步保存: 保存: 请求方式发生相应变化,同时颜色也发生变化,说明保存成功: ====== ...
- 《从零开始搭建游戏服务器》Eclipse和Tomcat安装配置
我选择用来进行服务器开发的语言是Java,开发流程更接近于JavaWeb,所以需要先为开发配置一个开发环境,需要配置的主要是Eclipse和Tomcat(Web工程的容器或管理工具). 一.资源下载: ...
- 【WEB基础】HTML & CSS 基础入门(6)超链接
超链接--文字链接 超链接[hyperlink]是网页中最为常见的元素之一,我们几乎可以在所有的网站页面中找到超链接.每个网站都不止一个页面,这些页面就是利用超链接进行串接.超链接帮我们实现了网页与网 ...
- stm32f103和s3c2440配置
stm32 s3c2440 外部晶振: 8MHz 12MHz
- Android 学习笔记---获取RadioGroup的选定值
1,获取RadioGroup控件: RadioGroup radioGroup = (RadioGroup)findViewById(R.id.myRadioGroup); 2,获取RadioButt ...
- 【kotlin】kotlin中List中添加List怎么操作
如题,List集合添加一个List集合怎么操作 如上,现在有了List<A>,A类中有个字段List<B>, 新创建一个List<B>,想把LIst<A> ...
- 创建git仓库及简单操作命令
1.把已有的项目代码纳入git管理 $ cd projectdir #projectdir项目代码所在的文件夹 $ git init 2.新建的项目直接使用git管理 $ cd dir #dir ...
- Ghost本地安装highlight.js使代码高亮
对于程序猿写博客来说,这代码高亮是起码的要求.可是Ghost本身没有支持高亮代码. 可是能够通过扩展来实现,它就是highlight.js--附官方站点,看了下首页介绍,真的非常强大,如今说说怎么进行 ...
- FFT用到的各种素数
int MOD; inline int mul(int a, int b){ return (long long)a * b % MOD; } int power(int a, int b){ ; ) ...