时间:2021-05-22
识别快递单号
这次跟老师做项目,这项目大概是流水线上识别快递上的快递单号。首先我尝试了解条形码的基本知识
百度百科:条形码
条形码(barcode)是将宽度不等的多个黑条和空白,按照一定的编码规则排列,用以表达一组信息的图形标识符。常见的条形码是由反射率相差很大的黑条(简称条)和白条(简称空)排成的平行线图案。条形码可以标出物品的生产国、制造厂家、商品名称、生产日期、图书分类号、邮件起止地点、类别、日期等许多信息,因而在商品流通、图书管理、邮政管理、银行系统等许多领域都得到广泛的应用。
条形码有多种,在我国广泛流传的是EAN13条形码(以下简称条形码),所以主要研究该种条形码的识别。
条形码位数说明:
条形码编码说明
条形码一共有8个区域:左侧空白区->起始符->左侧数据符->中间分隔符->右侧数据符->校验符->终止符->右侧空白区
还有这么一种理解编码方法
以宽度为编码,去掉起始码,终止码,中间分隔码,不管白条还是黑条都算一个编码,最窄一节为1(最窄的为单位宽度),两个单位宽度就是2,三单位长度为3,四单位宽度为4
四条(不管黑条还是白条都算条)代表一个数字
四条长度 数字 3211 0 2221 1 2122 2 1411 3 1132 4 1231 5 1114 6 1312 7 1213 8 3112 9
两种编码的图示
这就代表为 数字 1
校验
EAN13条形码一共有13位,最后1位是校验位,该位是通过前12位按照一定的步骤计算出来的。
如果按照一定的步骤处理识别出的前12位数据,如果计算结果和识别出的结果相等,识别正确;
如果不相等,则重新识别或纠错再校验或提示识别失败。
校验码计算方法
以下图所示的条形码举例说明:
条形码的位数起始位为最右一位,即校验位,检验码计算方法如下:
源码
#创建:2016/01/26#文件:BarCodeIdentification.py#作者:moverzp#功能:识别条形码import sysimport cv2DECODING_TABLE = { '0001101': 0, '0100111': 0, '1110010': 0, '0011001': 1, '0110011': 1, '1100110': 1, '0010011': 2, '0011011': 2, '1101100': 2, '0111101': 3, '0100001': 3, '1000010': 3, '0100011': 4, '0011101': 4, '1011100': 4, '0110001': 5, '0111001': 5, '1001110': 5, '0101111': 6, '0000101': 6, '1010000': 6, '0111011': 7, '0010001': 7, '1000100': 7, '0110111': 8, '0001001': 8, '1001000': 8, '0001011': 9, '0010111': 9, '1110100': 9, }EDGE_TABLE = { 2:{2:6,3:0,4:4,5:3}, 3:{2:9,3:'33',4:'34',5:5}, 4:{2:9,3:'43',4:'44',5:5}, 5:{2:6,3:0,4:4,5:3}, }INDEX_IN_WIDTH = (0, 4, 8, 12, 16, 20, 24, 33, 37, 41, 45, 49, 53)def get_bar_space_width(img): row = img.shape[0] *1/2 currentPix = -1 lastPix = -1 pos = 0 width = [] for i in range(img.shape[1]):#遍历一整行 currentPix = img[row][i] if currentPix != lastPix: if lastPix == -1: lastPix = currentPix pos = i else: width.append( i - pos ) pos = i lastPix = currentPix return widthdef divide(t, l): if float(t) / l < 0.357: return 2 elif float(t) / l < 0.500: return 3 elif float(t) / l < 0.643: return 4 else: return 5def cal_similar_edge(data): similarEdge = [] #先判断起始符 limit = float(data[1] + data[2] + data[3] ) / 3 * 1.5 if data[1] >= limit or data[2] >= limit or data[3] >= limit: return -1#宽度提取失败 index = 4 while index < 54: #跳过分隔符区间 if index==28 or index==29 or index==30 or index==31 or index==32: index +=1 continue #字符检测 T1 = data[index] + data[index+1] T2 = data[index+1] + data[index+2] L = data[index] + data[index+1] + data[index+2] + data[index+3] similarEdge.append( divide(T1, L) ) similarEdge.append( divide(T2, L) ) index += 4 return similarEdgedef decode_similar_edge(edge): barCode = [6]#第一个字符一定是6,中国区 for i in range (0, 24, 2):#每个字符两个相似边,共12个字符 barCode.append( EDGE_TABLE[edge[i]][edge[i+1]] ) return barCodedef decode_sharp(barCode, barSpaceWidth): for i in range(0, 13): if barCode[i] == '44': index = INDEX_IN_WIDTH[i] c3 = barSpaceWidth[index+2] c4 = barSpaceWidth[index+3] if c3 > c4: barCode[i] = 1 else: barCode[i] = 7 elif barCode[i] == '33': index = INDEX_IN_WIDTH[i] c1 = barSpaceWidth[index] c2 = barSpaceWidth[index+1] if c1 > c2: barCode[i] = 2 else: barCode[i] = 8 elif barCode[i] == '34': index = INDEX_IN_WIDTH[i] c1 = barSpaceWidth[index] c2 = barSpaceWidth[index+1] if c1 > c2: barCode[i] = 7 else: barCode[i] = 1 elif barCode[i] == '43': index = INDEX_IN_WIDTH[i] c2 = barSpaceWidth[index+1] c3 = barSpaceWidth[index+2] if c2 > c3: barCode[i] = 2 else: barCode[i] = 8def check_bar_code(barCode): evens = barCode[11]+barCode[9]+barCode[7]+barCode[5]+barCode[3]+barCode[1] odds = barCode[10]+barCode[8]+barCode[6]+barCode[4]+barCode[2]+barCode[0] sum = evens * 3 + odds if barCode[12] == (10 - sum % 10) % 10: return True else: return False#载入图像img = cv2.imread('res\google6.jpg')grayImg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#转换成单通道图像ret, grayImg = cv2.threshold(grayImg, 200, 255, cv2.THRESH_BINARY)#二值化grayImg = cv2.medianBlur(grayImg, 3)#中值滤波#提取条空宽度barSpaceWidth = get_bar_space_width(grayImg)print 'bar & space\'s numbers:', len(barSpaceWidth)#只有60是正确的print barSpaceWidth#计算相似边数值similarEdge = cal_similar_edge(barSpaceWidth)if similarEdge == -1: print 'barSpaceWidth error!' sys.exit()print 'similarEdge\'s numbers:', len(similarEdge)print similarEdge#相似边译码barCode = decode_similar_edge(similarEdge)#针对‘#'译码decode_sharp(barCode, barSpaceWidth)#校验valid = check_bar_code(barCode)valid = 1print 'barcode:\n', barCode if valid else 'Check barcode error!'height = img.shape[0]width = img.shape[1]cv2.line(grayImg, (0, height/2), (width, height/2),(0, 255, 0), 2)#画出扫描的行#显示图像cv2.imshow("origin", img)cv2.imshow("result", grayImg)key = cv2.waitKey(0)if key == 27: cv2.destroyAllWindows()第二种编码的程序
可惜这次遇到的是快递单上的条形码,非标准的EAN13条形码,暂时还不清楚这条形码的编码方式,所以换一个思路来识别快递单号,直接识别快递单上的数字快递单号
这里我用OCR引擎来识别,用的是Tesseract-OCR引擎
Tesseract-OCR引擎简介
OCR(Optical Character Recognition):光学字符识别,是指对图片文件中的文字进行分析识别,获取的过程。Tesseract的OCR引擎最先由HP实验室于1985年开始研发,至1995年时已经成为OCR业内最准确的三款识别引擎之一。然而,HP不久便决定放弃OCR业务,Tesseract也从此尘封。
数年以后,HP意识到,与其将Tesseract束之高阁,不如贡献给开源软件业,让其重焕新生--2005年,Tesseract由美国内华达州信息技术研究所获得,并求诸于Google对Tesseract进行改进、消除Bug、优化工作。
(由Google管理,所以下载地址“被墙”了,这里就不贴了)
还有一个模块就是 pytesseract 这包是对Google Tesseract的一层python封装需要配合 PIL 模块使用
所以此次识别快递单号,用到三个
源代码
有坑
在有 Git Bash调试时遇到了
Traceback (most recent call last): File "111.py", line 10, in <module> print u'验证码:' + str(code)UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)这一看就有事编码的坑了,我用的是python2.7 估计生3就没没坑了
但目前还是要解决这问题,对于这编码的问题有两种解决方法:
1.一个解决的方案在程序中加入以下代码:
2.是在python的Lib\site-packages文件夹下新建一个sitecustomize.py,内容为:
此时重启python解释器,执行sys.getdefaultencoding(),发现编码已经被设置为utf8的了,多次重启之后,效果相同,这是因为系统在python启动的时候,自行调用该文件,设置系统的默认编码,而不需要每次都手动的加上解决代码,属于一劳永逸的解决方法。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
使用Java语言,通过Tesseract-OCR对图片进行识别。1.Tesseract-OCR下载windows版本并安装。2.程序如下:a.ImageIOHe
环境centos7python3pytesseract只是tesseract-ocr的一种实现接口。所以要先安装tesseract-ocr(大名鼎鼎的开源的OC
一、Tesseract-OCR是什么AnOCREnginethatwasdevelopedatHPLabsbetween1985and1995…andnowat
java文字识别程序的关键是寻找一个可以调用的OCR引擎。tesseract-ocr就是一个这样的OCR引擎,在1985年到1995年由HP实验室开发,现在在G
java文字识别程序的关键是寻找一个可以调用的OCR引擎。tesseract-ocr就是一个这样的OCR引擎,在1985年到1995年由HP实验室开发,现在在G