1引言 条形码(简称条码)技术是集条码理论、光电技术、计算机技术、通信技术、条码印制技术于一体的一种自动识别技术。条形码是由宽度不同、反射率不同的条(黑色)和空(白色),按照一定的编码规则编制而成,用以表达一组数字或字母符号信息的图形标识符。条形码符号也可印成其它颜色,但两种颜色对光必须有不同的反射率,保证有足够的对比度。条码技术具有速度快、准确率高、可靠性强、寿命长、成本低廉等特点,因而广泛应用于商品流通、工业生产、图书管理、仓储标证管理、信息服务等领域。 本文针对EAN-13条码,介绍了其格式、编码规则等技术特点,并在Visual C++ 6.0环境下实现了一维条码的图像生成与识别,具有较好的应用价值。 2 EAN-13条形码简介 一维条码主要有EAN和UPC两种,其中EAN码是我国主要采取的编码标准。EAN是欧洲物品条码(European Article Number Bar Code)的英文缩写,是以消费资料为使用对象的国际统一商品代码。只要用条形码阅读器扫描该条码,便可以了解该商品的名称、型号、规格、生产厂商、所属国家或地区等丰富信息。 EAN通用商品条码是模块组合型条码,模块是组成条码的最基本宽度单位,每个模块的宽度为0.33毫米。在条码符号中,表示数字的每个条码字符均由两个条和两个空组成,它是多值符号码的一种,即在一个字符中有多种宽度的条和空参与编码。条和空分别由1~4个同一宽度的深、浅颜色的模块组成,一个模块的条表示二进制的“1”,一个模块的空表示二进制的“0”,每个条码字符共有7个模块。即一个条码字符条空宽度之和为单位元素的7倍,每个字符含条或空个数各为2,相邻元素如果相同,则从外观上合并为一个条或空,并规定每个字符在外观上包含的条和空的个数必须各为2个,所以EAN码是一种(7,2)码。 EAN条码字符包括0~9共10个数字字符,但对应的每个数字字符有三种编码形式,左侧数据符奇排列、左侧数据符偶排列以及右侧数据符偶排列。这样十个数字将有30种编码,数据字符的编码图案也有三十种,至于从这30个数据字符中选哪十个字符要视具体情况而定。在这里所谓的奇或偶是指所含二进制“1”的个数为偶数或奇数[2]。 2.1 EAN-13码的格式 EAN条形码有两个版本,一个是13位标准条码(EAN-13条码),另一个是8位缩短条码(EAN-8条码)。EAN-13条码由代表13位数字码的条码符号组成,如图1所示[1]。
图片看不清楚?请点击这里查看原图(大图)。 图1 EAN-13码的格式 前2位( 2.2 EAN-13条形码的构成 EAN-13条形码的构成如图2所示。
图2 典型EAN-13条形码的构成 (1)左、右侧空白:没有任何印刷符号,通常是空白,位于条码符号的两侧。用以提示阅读,准备扫描条码符号,共有18个模块组成(其中左侧空白不得少于9个模块宽度),一般左侧空白11个模块,右侧空白7个模块。 (2)起始符:条形码符号的第一位字符是起始符,它特殊的条空结构用于识别条形码符号的开始。由3个模块组成。 (3)左侧数据符:位于中间分隔符左侧,表示一定信息的条码字符,由42个模块组成。 (4)中间分隔符:位于条码中间位置的若干条与空,用以区分左、右侧数据符,由5个模块组成。 (5)右侧数据符:位于中间分隔符右侧,表示一定信息的条码字符,由35个模块组成。 (6)条码校验符:表示校验码的条码字符,用以校验条码符号的正确与否,由7个模块组成。 (7)终止符:条形码符号的最后一位字符是终止符,它特殊的条空结构用于识别条形码符号的结束。由3个模块组成。 一个条形码图案是数条黑色和白色线条组成,如图3所示。
图3 条形码图案实例 图案分成五个部分,从左至右分别为:起始部分、第一数据部分、中间部分、第二数据部分和结束部分。 (1)起始部分:由11条线组成,从左至右分别是8条白线,一条黑线,一条白线和一条黑线。 (2)第一数据部分:由42条线组成,是按照一定的算法形成的,包含了左侧数据符( (3)中间部分:由5条线组成,从左到右依次是白线,黑线,白线,黑线,白线。 (4)第二数据部分:由42条线组成,是按照一定的算法形成的,包含了右侧数据符( (5)结尾部分:由11条线组成,从左至右分别是一条黑线,一条白线和一条黑线,8条白线。 2.3 EAN-13的编码规则 EAN-13的编码是由二进制表示的。它的数据符、起始符、终止符、中间分隔符编码见表1。 表1 EAN-13编码
左侧数据符有奇偶性,它的奇偶排列取决于前置符,所谓前置符是国别识别码的第一位 表2 左侧数据符奇偶排列结合方式
2.4 EAN-13条形码的校验方法 校验码的主要作用是防止条形码标志因印刷质量低劣或包装运输中引起标志破损而造成扫描设备误读信息。作为确保商品条形码识别正确性的必要手段,条形码用户在标志设计完成后,代码的正确与否直接关系到用户的自身利益。对代码的验证,校验码的计算是标志商品质量检验的重要内容之一,应该谨慎严格,需确定代码无误后才可用于产品包装上。 下面是EAN-13条形码的校验码验算方法,步骤如下[3]: (1)以未知校验位为第1位,由右至左将各位数据顺序排队(包括校验码); (2)由第2位开始,求出偶数位数据之和,然后将和乘以3,得积 (3)由第3位开始,求出奇数位数据之和,得 (4)将 (5)用 (6)比较第1位的数据值与C的大小,若相等,则译码正确,否则进行纠错处理。 例如,设EAN-13码中数字码为6901038100578(其中校验码值为8),该条码字符校验过程为: 3 EAN-13条形码的生成 条形码的生成方法如下[3]: n (1)由 表3 映射表
(2
)将 表4 数字--字母映射表
(3)将 (4)按照两部分数据绘制条形码:1对应黑线,0对应白线。 例如,假设一个条形码的数据码为:6901038100578。 4 条形码识别 4.1条码识别的基本原理 EAN-13是一种(7, 2)码,即每个字符的总宽度为7个模块宽,交替由两个条和两个空组成,而每个条空的宽度不超过4个模块,如图4所示。
图片看不清楚?请点击这里查看原图(大图)。 图4 EAN-13条码宽度的定义 图4中 用 由于条码印刷和图像采集设备的限制,在图像采集时边缘部分还存在着半像素问题,实际扫描后得到的图像会出现一定程度的边缘模糊,尤其当条码密度较大,条空间距较小时边缘模糊更为明显。边缘出现模糊时,将导致寻找条空边缘时产生一定偏差,当这个偏差超过半个模块宽度时,便会出现误码。如果再考虑到流通过程中磨损、水渍浸泡等因素引起的图像缺陷,在这种情况下如果用边缘检测的方法确定条空序列会大大降低条码的识别率。本文采用的方法为:以起始模块的中心为起始中心、一个单位模块宽度为间距来检测条空序列。 4.2 条形码扫描方向的判别 为了能够正确地解译条形码,在解译条形码符号所表示的数据之前,需要先进行条形码扫描方向的判别,EAN-13的起始字符和终止字符的编码结构都是“101”,只能通过它进行码制的判别(对于多种条码识别的时候,其它码制的条码起始字符和终止字符都不是“101”),但是不能通过起始字符和终止字符来判别它的扫描方向。由EAN-13码的编码结构可知,它的右侧字符为全偶,而左侧字符的奇偶顺序由前置符决定,没有全偶的,从而可以利用此原理来确定EAN-13码的扫描方向。如果扫描到的前6个字符为全偶,即为反向扫描,否则为正向扫描。 4.3条形码字符的判别方法 从上述条码识别原理知,它的逻辑值可以通过和单位模块比较判别。这种方法对于印刷质量很好、没有缺陷的条码很适用,但是对于条码印刷质量存在缺陷,则不能正确地解译。因此本文提出了一种解决此类问题的较好方法,即相似边距离测量方法。
图5条码字符宽度示图 相似边距离就是相邻条和空的宽度之和,如图5中的
表5列出了正向译码时EAN-13条码字符值与归一化值 表5 EAN-13条码字符值与归一化值的对应关系(正向译码)
表6 EAN-13条码字符值与归一化值的对应关系(反向译码)
表7和表8分别为正向译码和反向译码时EAN-13条码编码与归一化值的对应关系。 表7 EAN-13条码编码与归一化值的对应关系(正向译码)
表8 EAN-13条码字符值与归一化值的对应关系(反向译码)
由表5~8可以看出,条形码编码和归一化值在多数情况下呈现一一对应的关系,只要确定了归一化值就能确定字符值,但是有四种情况例外。以正向译码为例,在表6中,左侧奇字符和右侧偶字符1, 7归一化值均为44,左侧奇字符和右侧偶字符2, 8归一化值均为33,左侧偶字符1, 7归一化值均为34,左侧偶字符2, 8归一化值均为43,这几种情况可以根据字符的条空宽度 进一步判别。表9为1728字符标准条空宽度值,其中字符上有“-”的对应条,否则对应空。 表9 1728字符标准条空宽度值
根据表9中各字符条空宽度的特点可知:①对于左侧奇字符、右侧偶字符1和7,可通过比较 采用相似边距离归一化的条码识别方法,当条码质量存在缺陷使得实际测量值和条码应该具有的理论值有较大偏差时,仍能正确解译。例如对于左侧奇字符“0”进行译码,该字符的四个元素宽度的理论值应该是 4.4纠错处理 采用相似边距离归一化的译码方法能够在一定程度上消除条、空误差对译码识别的影响。当系统误差特别是条码印刷误差较大导致 (1)如果条码字符的 (2)当字符数据为2、8、1、7时,由于条码宽度不精确导致误码,即2判成8、1判成7,或反之。分析这种误码相对于校验位的差值有一定规律,因此可利用此规律进行纠错。由EAN-13校验方法知:当偶数位上有2错译成8或1错译成7时,计算得到的实译值与校验值差-8或2,反之8错译成2或7错译成1时,计算得到的实译值与校验值差8或-2;当奇数位上有2错译成8或1错译成7时,计算得到的实译值与校验值差-6或4,反之,8错译成2或7错译成1时,计算得到的实译值与校验值差6或-4;当然别的字符译错也可能出现这些差值,但几率很小,可以不予考虑。这样若程序校验没通过,可加一个判断,根据差值判断其属于上述哪种情况,找出出错的字符并纠正。 5 程序实现 5.1 应用Visual C++生成条形码图像 5.1 1 创建工程文件 (1)打开VC++ 6.0,点击“File”菜单的“New”菜单项,在出现的界面中选定“Projects”栏,点击“MFC APPWizard(exe)”,工程文件名为Generator。按“确定”按纽,进入MFC APPWizard。 (2)在MFC APPWizard第一步选择Single document文档类型。第二步和第三步按默认方式。第四步中去掉“Docking toolbar”、“Initial status bar”、“Printing and print preview”前面的“√”,即不选该三项。然后点击“Advanced…”,在出现的界面中填写“File extension”为“bmp”。第五步和第六步按默认方式。最终生成工程Generator。 (3)修改菜单。①增加“操作”菜单;②删除“编辑”菜单;③修改“帮助”菜单。参见工程文件。 (4)插入两个对话框(IDD_WELCOME、IDD_GIVECODE)并修改这两个对话框。参见工程文件。 5.1.2 类代码编制 (1)在Generator工程中增加新类CWelcomeDlg,类型为Generic Class。 (2)在Generator工程中增加新类CGIveCodeDlg,类型为Generic Class。 (3)点击“View”菜单的“ClassWizard”菜单项,在出现的界面中,选择Class Name为“, CGeneratorView”,增加成员函数,Object Ids、Messages、Member functions分别为:①ID_EDIT_GIVE、COMMAND、ON_ID_EDIT_GIVE:COMMAND;②ID_FILE_SAVE、COMMAND、ON_ID_FILE_SAVE。 (4)给类GeneratorView添加成员变量,参见源程序Generatorview.h。 (5)打开文件GeneratorView.h,增加代码,参见源程序。打开文件GeneratorView.cpp,增加代码,参见源程序。 (6)点击“View”菜单的“ClassWizard”菜单项,在出现的界面中,选择Class Name为“CWelcomeDlg”,增加成员函数,Object Ids、Messages、Member functions分别为:IDOK、BN_CLICKED、OnOK()。 (7)点击“View”菜单的“ClassWizard”菜单项,在出现的界面中,选择Class Name为“CMainFrame”,增加成员函数,Object Ids、Messages、Member functions分别为:CmainFrame、WM_CREATE、OnCreate()。 (8)打开文件MainFrame.cpp,增加“#include "WelcomeDlg.h"”,输入代码,参见源程序。 (9)打开GeneratorView.cpp源文件,增加语句“#include "GiveCodeDlg.h" ,#inc, lude "GiveSizeDlg.h", #include <map> ,#include <algorithm>”,输入成员函数代码,参见源程序。 (10)编译、连接、运行。 5.2 应用Visual C++识别条形码图像 5.2.1创建工程文件 (1)打开VC++ 6.0,点击“File”菜单的“New”菜单项,在出现的界面中选定“Projects”栏,点击“MFC APPWizard(exe)”,工程文件名为Recognizor。按“确定”按纽,进入MFC APPWizard。 (2)MFC APPWizard第一步选择Single document文档类型。第二步和第三步按默认方式。第四步中去掉“Docking toolbar”、“Initial status bar”、“Printing and print preview”前面的“√”,即不选该三项。然后点击“Advanced…”,第四步、第五步和第六步按默认方式。最终生成工程Recognizor。 (3)修改菜单。①修改“文件”菜单;②删除“编辑”菜单;③修改“帮助”菜单。参见工程文件。 (4)插入一个对话框(IDD_WELCOME),参见工程文件。 5.2.2 类代码编制 (1)在Recognizor工程中增加新类CWelcomeDlg,类型为Generic Class。 (2)给类RecognizorView添加成员变量,参见源程序Recognizorview.h。 (3)点击“View”菜单的“ClassWizard”菜单项,在出现的界面中,选择Class Name为“CRecognizorView”,增加成员函数,Object Ids、Messages、Member functions分别为:ID_FILE_OPEN、COMMAND、ON_ID_FILE_OPEN:COMMAND; (4)点击“View”菜单的“ClassWizard”菜单项,在出现的界面中,选择Class Name为“CMainFrame”,增加成员函数,Object Ids、Messages、Member functions分别为:CmainFrame、WM_CREATE、ON_WM_CREATE; (5)打开文件MainFrame.cpp,增加“#include "WelcomeDlg.h"”,增加代码,参见源程序。 (6)打开RecognizorView.cpp源文件,输入成员函数,参见源程序。 (7)编译、连接、运行。 6 结论 本文介绍了一维条码格式、编码规则等技术特点,以及条码图像生成与识别的基本原理,并用Visual C++实现了条码图像生成和具有一定纠错能力的条码识别软件。尽管关于一维条码识别的设备很多,但这些都是针对于光电识别的。光电识别设备只能识别印刷质量好的条码,而通过图像处理技术辨识一维条码能对质量差的条码达到好的识别效果,因此它明显优于光电识别设备。 参考文献 1.熊小寒.条形码技术与标准化[M].天津:天津大学出版社,1992. 2.李金哲等.条形码自动识别技术[M].辽宁:科学技术出版社,1993. 3.苏彦华等.数字图像识别技术典型案例[M]. 北京:人民邮电出版社,2004. (责任编辑:admin) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||



