/***
* 基于OpenCV的条形码识别算法实现
* 适用范围:EAN13、Code39、Code93、Code128
* 适用读者:初级图像处理学习者,高手路过勿喷,仅供参考,互相学习
* 编码方式:本文采用C和C++混合编写
* 作者邮箱:xuxin0312@foxmail.com,欢迎交流学习
***/
#include <highgui.h>
#include "cv.h"
#include <string.h>
#include <iostream>
#include <unordered_map>
#include<time.h>
using namespace std;
//常用的编码方式
int const EAN13 = 1;
int const Code39 = 2;
int const Code93 = 3;
int const Code128 = 4;
string getCodeBar(IplImage* source, int encoding);
string getCodeBar(IplImage* source);
int getEncoding(IplImage* source);
bool isEAN13(IplImage* source);
bool isCode39(IplImage* source);
bool isCode93(IplImage* source);
bool isCode128(IplImage* source);
void getBaseAndStart(IplImage* source, int lineHight, int threshold,int* base, int* start);
int getNumOfPixel(IplImage* source, int lineHight,int threshold, int* index);
string getDigitsEAN13(IplImage* source);
string parseEAN13(string code);
string getDigitsCode39(IplImage* source);
string parseCode39(string code);
string getDigitsCode93(IplImage* source);
string parseCode93(string code);
string getDigitsCode128(IplImage* source);
string parseCode128(string code);
int main() {
char* path = "D:\\g.jpg";//路径为自定义,条形码尽量居于图片的中间位置,本算法未实现条码的定位。
int encoding = Code128;//上面定义了几种编码方式
IplImage* img = cvLoadImage(path);
clock_t start,finish;
double totaltime;
start = clock();
//string code = getCodeBar(img, encoding);//条形码检测入口函数,指定编码方式
string code = getCodeBar(img);//条形码检测入口函数,未指定编码方式
finish = clock();
totaltime=finish-start;
cout<<"此程序的运行时间为"<<totaltime<<"毫秒!"<<endl;
cout<<"条形码为 :"<<code<<endl;
cvNamedWindow("Example",CV_WINDOW_AUTOSIZE);
cvShowImage("Example",img);
cvWaitKey(0);
cvReleaseImage(&img);
cvDestroyWindow("Example");
return 0;
}
string getCodeBar(IplImage* source) {
string result = "";
int encoding = getEncoding(source);
result = getCodeBar(source,encoding);
return result;
}
string getCodeBar(IplImage* source,int encoding) {
string codeDigit="";
string result="";
switch (encoding) {
case EAN13:
codeDigit = getDigitsEAN13(source);
result = parseEAN13(codeDigit);
break;
case Code39:
codeDigit = getDigitsCode39(source);
result = parseCode39(codeDigit);
break;
case Code93:
codeDigit = getDigitsCode93(source);
result = parseCode39(codeDigit);
break;
case Code128:
codeDigit = getDigitsCode128(source);
result = parseCode128(codeDigit);
break;
}
return result;
}
/*
* 方法描述:获取条码的编码方式
* 输入:图像文件source
* 输出:编码方式,默认返回EAN13
*/
int getEncoding(IplImage* source) {
if(isEAN13(source))
return EAN13;
else if(isCode39(source))
return Code39;
else if(isCode93(source))
return Code93;
else if(isCode128(source))
return Code128;
else
return EAN13;//程序默认为EAN13编码方式
}
/*
* 方法描述:判断条码的编码方式是否为EAN13
* 输入:图像文件source
* 输出:true/false
*/
bool isEAN13(IplImage* source) {
string code = "";
code = getDigitsEAN13(source);
if(code.length() == 95 && code.substr(0,3) == "101" && code.substr(92,3) == "101")
return true;
else
return false;
}
/*
* 方法描述:判断条码的编码方式是否为Code39
* 输入:图像文件source
* 输出:true/false
*/
bool isCode39(IplImage* source) {
int height = source->height;
int width = source->width;
int start = 0;
int base = 0;
int threshold = 128;
int lineHight = height/2;
string code = "";
getBaseAndStart(source,lineHight,threshold,&base,&start);
int index = start;
while(true) {
if(index >= width - 10)
break;
if(code.length() >= 9)
break;
int numOfPixel = getNumOfPixel(source, lineHight,threshold,&index);//统计相同类型(条/空白)的像素的个数
int numOfDigit = (int) ((double) numOfPixel / base + 0.5);
if(numOfDigit > 1)
code += "1";
else
code += "0";
}
if(code == "010010100")
return true;
else
return false;
}
/*
* 方法描述:判断条码的编码方式是否为Code93
* 输入:图像文件source
* 输出:true/false
*/
bool isCode93(IplImage* source) {
int height = source->height;
int width = source->width;
int start = 0;
int base = 0;
int threshold = 128;
int lineHight = height/2;
string code = "";
getBaseAndStart(source,lineHight,threshold,&base,&start);
int index = start;
while(true) {
if(index >= width - 10)
break;
if(code.length() >= 6)
break;
int numOfPixel = getNumOfPixel(source, lineHight,threshold,&index);//统计相同类型(条/空白)的像素的个数
int numOfDigit = (int) ((double) numOfPixel / base + 0.5);
code.append(1,'0' + numOfDigit);
}
if(code == "111141")
return true;
else
return false;
}
/*
* 方法描述:判断条码的编码方式是否为Code128
* 输入:图像文件source
* 输出:true/false
*/
bool isCode128(IplImage* source) {
int height = source->height;
int width = source->width;
int start = 0;
int base = 0;
int threshold = 128;
int lineHight = height/2;
string code = "";
getBaseAndStart(source,lineHight,threshold,&base,&start);
base = base / 2;//因为Code128起始符为2,为base宽度的两倍
int index = start;
while(true) {
if(index >= width - 10)
break;
if(code.length() >= 6)
break;
int numOfPixel = getNumOfPixel(source, lineHight,threshold,&index);//统计相同类型(条/空白)的像素的个数
int numOfDigit = (int) ((double) numOfPixel / base + 0.5);
code.append(1,'0' + numOfDigit);
}
if(code == "211214")
return true;
return false;
}
/*
* 方法描述:获取编码方式为EAN13的间接code
* 输入:图像文件source
* 输出:间接的EAN13 code
*/
string getDigitsEAN13(IplImage* source) {
int height = source->height;
int width = source->width;
int start = 0;
int base = 0;
int threshold = 128;
int lineHight = height/2;//默认采取图像中间的一条线来提取间接code
string code = "";
getBaseAndStart(source,lineHight,threshold,&base,&start);
int index = start;
while(true) {
if(code.length() >= 95)
break;
if(index >= width - 10)
break;
CvScalar scalar = cvGet2D(source,lineHight,index);
int temp = 0.114 * scalar.val[0] + 0.587 * scalar.val[1] + 0.299 * scalar.val[2];//BGR转化为灰度图像公式
int bias = temp - threshold;//用来判断为空白还是条纹
int numOfPixel = getNumOfPixel(source, lineHight,threshold,&index);//统计相同类型(条/空白)的像素的个数
int numOfDigit = (int) ((double) numOfPixel / base + 0.5);//在EAN13中代表宽条代表几个数字(0/1)
if(numOfDigit >= 1) {
for(int j = 0; j < numOfDigit; j++) {//采用循环来显示多个相同数字
if(bias < 0)
code = code + "1";
else
code = code + "0";
}
}
}
return code;
}
/*
* 方法描述:获取编码方式为Code39的间接code
* 输入:图像文件source
* 输出:间接的Code39 code
*/
string getDigitsCode39(IplImage* source) {
int height = source->height;
int width = source->width;
int start = 0;
int base = 0;
int threshold = 128;
int lineHight = height/2;
string digitFlag = "";//起始符或终止符
int flag = 0;//0表示digitFlag代表起始符,1表示digitFlag代表终止符
string code = "";
getBaseAndStart(source,lineHight,threshold,&base,&start);
int index = start;
while(true) {
if(index >= width - 10)
break;
int numOfPixel = getNumOfPixel(source, lineHight,threshold,&index);//统计相同类型(条/空白)的像素的个数
int numOfDigit = (int) ((double) numOfPixel / base + 0.5);
if(numOfDigit > 1) {
code += "1";
digitFlag += "1";
} else {
code += "0";
digitFlag += "0";
if(digitFlag.length() == 10) {
if(flag == 0 && digitFlag.substr(0,9) == "010010100") {
digitFlag = "";
flag = 1;
} else if(flag == 0 && digitFlag.substr(0,9) != "010010100") {
break;
} else if(flag == 1 && digitFlag.substr(0,9) == "010010100") {
break;
} else if(flag ==
基于OpenCV的多种条形码识别算法
需积分: 32 108 浏览量
2016-06-23
14:52:20
上传
评论 15
收藏 821KB RAR 举报
AllenXu
- 粉丝: 6
- 资源: 4
最新资源
- 《CKA/CKAD应试指南/从docker到kubernetes 完全攻略》学习笔记 第1章docker基础(1.1-1.4)
- 基于python实现的水下压缩空气储能互补系统建模仿真与经济效益分析+源代码+论文
- 华中科技大学-自然语言处理实验,Bi-LSTM+CRF的中文分词框架,并且利用基于深度学习的方法进行中文命名实体识别++源码报告
- 基于动态罚函数的铁路车流分配与径路优化模型python源码
- 鱼群算法求解组环问题python源码+文档说明
- 基于决策优化的多波束测深测线规划模型MATLAB代码
- 课程设计-基于python实现的多目标优化算法求解带时间窗的车辆路径规划问题+源代码+文档说明+界面截图+pptx
- 基于通信信号与通信系统的MATLAB仿真源码-课程设计
- 嵌入式-信号机制(概念,发送,定时,捕捉,SIGCHLD 信号实现回收子进程)
- c语言管理系统大一大二笔记
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈