一维条形码生成与识别技术

ぃ、小莉子 提交于 2019-11-27 07:28:51

核心提示:1引言 条形码(简称条码)技术是集条码理论、光电技术、计算机技术、通信技术、条码印制技术于一体的一种自动识别技术,条形码是由宽度不同、反射率不同的条(黑色)和空(白色),一维条形码生成与识别技术,按照一定的编码规则编制而成,用以表达一组数字或字母符号信息的图形标识符,参考文献1.熊小寒.条形码技术与标准化[M].天津:

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位( ~ ,欧共体12国采用)或前3位( ~ ,其他国家采用)数字为国家或地区代码,称为前缀码或前缀号。例如:我国为690,日本为49*,澳大利亚为93*等(其中的“*”表示0~9的任意数字)。前缀后面的5位( ~ )或4位( ~ )数字为商品制造商的代码,是由该国编码管理局审查批准并登记注册的。厂商代码后面的5位( ~ )数字为商品代码或商品项目代码,用以表示具体的商品项目,即具有相同包装和价格的同一种商品。最后一位数字为校验码,用以提高数据的可靠性和校验数据输入的正确性,校验码的数值按国际物品编码协会规定的方法计算。

2.2 EAN-13条形码的构成

EAN-13条形码的构成如图2所示。

左侧

空白

起始符

左侧数据符

6位数字

中间

分隔符

右侧数据符

6位数字

校验符

1位数字

终止符

右侧

空白

图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编码

字符

二进制表示

左侧数据符

右侧数据符

奇性字符(A组)

偶性字符(B组)

偶性字符(C组)

0

1

2

3

4

5

6

7

8

9

起始符

中间分隔符

终止符

0001101

0011001

0010011

0111101

0100011

0110001

0101111

0111011

0110111

0001011

0100111

0110011

0011011

0100001

0011101

0111001

0000101

0001001

0001001

0010111

1110010

1100110

1101100

1000010

1011100

1001110

1010000

1000100

1001000

1110100

101

01010

101

左侧数据符有奇偶性,它的奇偶排列取决于前置符,所谓前置符是国别识别码的第一位 ,该位以消影的形式隐含在左侧六位字符的奇偶性排列中,这是国际物品编码标准版的突出特点。前置符与左侧六位字符的奇偶排列组合方式的对应关系见表2,实际上由表2这种编码规定可看出, 与这种组合方式是一一对应固定不变的。例如:中国的国别识别码为“690”,因此它的前置符为“6”,左侧数据符的奇偶排列为 “OEEEOO”[3],“E”表示偶字符,“O”表示奇字符。

表2 左侧数据符奇偶排列结合方式

前置符

左侧数据符奇、偶排列

前置符

左侧数据符奇、偶排列

0

O   O   O   O   O   O

5

O   E   E   O   O   E

1

O   O   E   O   E   E

6

O   E   E   E   O   O

2

O   O   E   E   O   E

7

O   E   O   E   O   E

3

O   O   E   E   E   O

8

O   E   O   E   E   O

4

O   E   O   O   E   E

9

O   E   E   O   E   O

2.4 EAN-13条形码的校验方法

校验码的主要作用是防止条形码标志因印刷质量低劣或包装运输中引起标志破损而造成扫描设备误读信息。作为确保商品条形码识别正确性的必要手段,条形码用户在标志设计完成后,代码的正确与否直接关系到用户的自身利益。对代码的验证,校验码的计算是标志商品质量检验的重要内容之一,应该谨慎严格,需确定代码无误后才可用于产品包装上。

下面是EAN-13条形码的校验码验算方法,步骤如下[3]

(1)以未知校验位为第1位,由右至左将各位数据顺序排队(包括校验码);

(2)由第2位开始,求出偶数位数据之和,然后将和乘以3,得积 ;

(3)由第3位开始,求出奇数位数据之和,得 ;

(4)将 和 相加得和 ;

(5)用 除以10,求得余数,并以10为模,取余数的补码,即得校验位数据值 ;

(6)比较第1位的数据值与C的大小,若相等,则译码正确,否则进行纠错处理。

例如,设EAN-13码中数字码为6901038100578(其中校验码值为8),该条码字符校验过程为:, , = + =82, 除以10的余数为2,故 ,译码正确。

3 EAN-13条形码的生成

条形码的生成方法如下[3]

n    (1)由 根据表3产生和 ~ 匹配的字母码,该字母码有6个字母组成,字母限于A和B。

表3 映射表

字母码

字母码

 

0

AAAAAA

5

ABBAAB

1

AABABB

6

ABBBAA

2

AABBAB

7

ABABAB

3

AABBBA

8

ABABBA

4

ABAABB

9

ABBABA

(2

字母码

字母码

 

0

AAAAAA

5

ABBAAB

1

AABABB

6

ABBBAA

2

AABBAB

7

ABABAB

3

AABBBA

8

ABABBA

4

ABAABB

9

ABBABA

)将 ~ 和 产生的字母码按位进行搭配,来产生一个数字--字母匹配对。并通过查表4生成条形码的第一数据部分。

表4 数字--字母映射表

数字-字母匹配对

二进制信息

数字-字母匹配对

二进制信息

0A

0001101

0B

0100111

0C

1110010

1A

0011001

1B

0110011

1C

1100110

2A

0010011

2B

0011011

2C

1101100

3A

0111101

3B

0100001

3C

1000010

4A

0100011

4B

0011101

4C

1011100

5A

0110001

5B

0111001

5C

1001110

6A

0101111

6B

0000101

6C

1010000

7A

0111011

7B

0010001

7C

1000100

8A

0110111

8B

0001001

8C

1001000

9A

0001011

9B

0010111

9C

1110100

(3)将 ~ 和C进行搭配,并通过查表4生成条形码的第二数据部分。

(4)按照两部分数据绘制条形码:1对应黑线,0对应白线。

例如,假设一个条形码的数据码为:6901038100578。 =6,对应的字母码为ABBBAA,~ 和 产生的字母码按位进行搭配结果为9A、0B、1B、0B、3A、8A,查表4得第一部分数据的编码分别为0001011、0100111、0110011、0100111、0111101、0110111; ~ 和C进行搭配结果为1C、0C、0C、5C、7C、8C,查表4得第二部分数据的编码分别为1100110、1110010、1110010、1001110、1000100、1001000。

4 条形码识别

4.1条码识别的基本原理

EAN-13是一种(7, 2)码,即每个字符的总宽度为7个模块宽,交替由两个条和两个空组成,而每个条空的宽度不超过4个模块,如图4所示。

 

图片看不清楚?请点击这里查看原图(大图)。

图4  EAN-13条码宽度的定义

图4中 表示当前字符中四个相邻条、空的宽度, 是一个字符的宽度,满足:, 为整数 ;且 。

用 表示当前字符单位模块的宽度,则 。令 , 。由 的值可以得到编码。例如:若 ,且条码的排列为条—空—条—空,则可知当前字符的编码为1000100,是右侧偶字符7。,且条码的排列为空—条—空—条,则可知当前字符的编码为0001011,是左侧偶字符9。

由于条码印刷和图像采集设备的限制,在图像采集时边缘部分还存在着半像素问题,实际扫描后得到的图像会出现一定程度的边缘模糊,尤其当条码密度较大,条空间距较小时边缘模糊更为明显。边缘出现模糊时,将导致寻找条空边缘时产生一定偏差,当这个偏差超过半个模块宽度时,便会出现误码。如果再考虑到流通过程中磨损、水渍浸泡等因素引起的图像缺陷,在这种情况下如果用边缘检测的方法确定条空序列会大大降低条码的识别率。本文采用的方法为:以起始模块的中心为起始中心、一个单位模块宽度为间距来检测条空序列。

4.2 条形码扫描方向的判别

为了能够正确地解译条形码,在解译条形码符号所表示的数据之前,需要先进行条形码扫描方向的判别,EAN-13的起始字符和终止字符的编码结构都是“101”,只能通过它进行码制的判别(对于多种条码识别的时候,其它码制的条码起始字符和终止字符都不是“101”),但是不能通过起始字符和终止字符来判别它的扫描方向。由EAN-13码的编码结构可知,它的右侧字符为全偶,而左侧字符的奇偶顺序由前置符决定,没有全偶的,从而可以利用此原理来确定EAN-13码的扫描方向。如果扫描到的前6个字符为全偶,即为反向扫描,否则为正向扫描。

4.3条形码字符的判别方法

从上述条码识别原理知,它的逻辑值可以通过和单位模块比较判别。这种方法对于印刷质量很好、没有缺陷的条码很适用,但是对于条码印刷质量存在缺陷,则不能正确地解译。因此本文提出了一种解决此类问题的较好方法,即相似边距离测量方法。

 

图5条码字符宽度示图

相似边距离就是相邻条和空的宽度之和,如图5中的 ,定义 的归一化值 和 如下:

      

表5列出了正向译码时EAN-13条码字符值与归一化值 的对应关系,表6列出了反向译码时EAN-13条码字符值与归一化值 的对应关系,其中“E”表示偶字符,“O”表示奇字符。

表5 EAN-13条码字符值与归一化值的对应关系(正向译码)

   

2

3

4

5

 

 

2

O6

EO

O4

E3

 

3

E9

O2或O8

E1或E7

O5

 

4

O9

E2或E8

O1或O7

E5

 

5

E6

O0

E4

O3

 

表6 EAN-13条码字符值与归一化值的对应关系(反向译码)

   

2

3

4

5

 
 

2

E6

O0

E4

O3

 

3

O9

E2或E8

O1或O7

E5

 

4

E9

O2或O8

E1或E7

O5

 

5

O6

E0

O4

E3

 

表7和表8分别为正向译码和反向译码时EAN-13条码编码与归一化值的对应关系。

表7 EAN-13条码编码与归一化值的对应关系(正向译码)

字符

左奇字符

编码

 

左偶字符

编码

 

右偶字符

编码

 

0

1

2

3

4

5

6

7

8

9

0001101

0011001

0010011

0111101

0100011

0110001

0101111

0111011

0110111

0001011

(5,3)

(4,4)

(3,3)

(5,5)

(2,4)

(3,5)

(2,2)

(4,4)

(3,3)

(4,2)

0100111

0110011

0011011

0100001

0011101

0111001

0000101

0010001

0001001

0010111

(2,3)

(3,4)

(4,3)

(2,5)

(5,4)

(4,5)

(5,2)

(3,4)

(4,3)

(3,2)

1110010

1100110

1101100

1000010

1011100

1001110

1010000

1000100

1001000

1110100

(5,3)

(4,4)

(3,3)

(5,5)

(2,4)

(3,5)

(2,2)

(4,4)

(3,3)

(4,2)

表8 EAN-13条码字符值与归一化值的对应关系(反向译码)

字符

左奇字符

编码

 

左偶字符

编码

 

右偶字符

编码

 

0

1

2

3

4

5

6

7

8

9

1011000

1001100

1100100

1011110

1100010

1000110

1111010

1101110

1110110

1101000

(2,3)

(3,4)

(4,3)

(2,5)

(5,4)

(4,5)

(2,2)

(3,4)

(4,3)

(3,2)

1110010

1100110

1101100

1000010

1001110

1001110

1010000

1000100

1001000

1110100

(5,3)

(4,4)

(3,3)

(5,5)

(2,4)

(3,5)

(2,2)

(4,4)

(3,3)

(4,2)

0100111

0110011

0011011

0100001

0011101

0111001

0000101

0010001

0001001

0010111

(2,3)

(3,4)

(4,3)

(2,5)

(5,4)

(4,5)

(5,2)

(3,4)

(4,3)

(3,2)

由表5~8可以看出,条形码编码和归一化值在多数情况下呈现一一对应的关系,只要确定了归一化值就能确定字符值,但是有四种情况例外。以正向译码为例,在表6中,左侧奇字符和右侧偶字符1, 7归一化值均为44,左侧奇字符和右侧偶字符2, 8归一化值均为33,左侧偶字符1, 7归一化值均为34,左侧偶字符2, 8归一化值均为43,这几种情况可以根据字符的条空宽度 进一步判别。表9为1728字符标准条空宽度值,其中字符上有“-”的对应条,否则对应空。

表9 1728字符标准条空宽度值

字符值

左奇字符编码

条空宽度值

左偶字符编码

条空宽度值

右偶字符编码

条空宽度值

1

0011001

 

0110011

1100110

   

2

0010011

0011011

1101100

     

7

0111011

0010001

1000100

     

8

0110111

0001001

1001000

     

根据表9中各字符条空宽度的特点可知:①对于左侧奇字符、右侧偶字符1和7,可通过比较与 来判别,若 > ,则为字符1,反之为7;②对于左侧奇字符、右侧偶字符2和8,可通过比较 与 来判别,若 > ,则为字符8,反之为2;③对于左侧偶字符1和7,可通过比较 与 来判别,若 > ,则为字符7,反之为1;④对于左侧偶字符2和8,可通过比较 与 来判别,若 > ,则为字符2,反之为8。

采用相似边距离归一化的条码识别方法,当条码质量存在缺陷使得实际测量值和条码应该具有的理论值有较大偏差时,仍能正确解译。例如对于左侧奇字符“0”进行译码,该字符的四个元素宽度的理论值应该是 ,但是由于印刷等原因的影响,实际上测量值是 。如果只根据元素宽度的测量值进行译码,那么这四个元素的宽度测量值四舍五入取整后分别为3、3、1、1,从而造成译码错误。若采取相似边距离归一化的条码识别方法进行译码,此时 ,由表7知字符编码为左侧奇字符“0”。可见利用相似边距离归一化的条码识别方法判别字符值,可以得到比较满意的效果。

4.4纠错处理

采用相似边距离归一化的译码方法能够在一定程度上消除条、空误差对译码识别的影响。当系统误差特别是条码印刷误差较大导致 、 改变时,译码将出错。因此译码软件应具有一定的纠错能力,以减少条空宽度值不精确的影响,提高条码识别率[1]。纠错主要从以下两方面进行:

(1)如果条码字符的 或 在临界位置,当条或空的宽度有误差时,就会导致 或 的整数值增1或减1。如果 和 中只有一个发生错误,则引起该字符的奇偶性、字符值的改变,如果 和 都出错,则引起该字符值的改变,但奇偶性未变。实际情况中第一种现象出现的概率比第二种情况大得多,因此本文主要对第一种情况进行纠错。由表1和表2可知,右侧字符为全偶字符排列,左侧字符有10种奇偶排列,这11种排列构成有效的排列集合,把所译的字符串奇偶排列与有效的奇偶排列对比,判断是否为排列集合成员。若是,所译的字符串不作任何处理;若不是,所译码出错,并找出 或 哪个处在临界值,修改它的归一化整数值,这样可实现纠错。

(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.

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!