亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Python識別快遞條形碼及Tesseract-OCR使用詳解

系統 2007 0

識別快遞單號

這次跟老師做項目,這項目大概是流水線上識別快遞上的快遞單號。首先我嘗試了解條形碼的基本知識

百度百科:條形碼

條形碼(barcode)是將寬度不等的多個黑條和空白,按照一定的編碼規則排列,用以表達一組信息的圖形標識符。常見的條形碼是由反射率相差很大的黑條(簡稱條)和白條(簡稱空)排成的平行線圖案。條形碼可以標出物品的生產國、制造廠家、商品名稱、生產日期、圖書分類號、郵件起止地點、類別、日期等許多信息,因而在商品流通、圖書管理、郵政管理、銀行系統等許多領域都得到廣泛的應用。

條形碼有多種,在我國廣泛流傳的是EAN13條形碼(以下簡稱條形碼),所以主要研究該種條形碼的識別。

條形碼位數說明:

  • 條形碼一共有13位
  • 前2位或者前3位稱為前綴,表示國家、地區或者某種特定的商品類型
  • 中國區條形碼開頭:690~699
  • 圖書類條形碼開頭:978~979
  • 前綴后的4位或者5位稱為廠商代碼,表示產品制造商
  • 廠商代碼后5位稱為商品代碼,表示具體的商品項目
  • 最后1位是校驗碼,根據前12位計算而出,可以用來防偽以及識別校驗

條形碼編碼說明

條形碼一共有8個區域:左側空白區->起始符->左側數據符->中間分隔符->右側數據符->校驗符->終止符->右側空白區

Python識別快遞條形碼及Tesseract-OCR使用詳解_第1張圖片

  • 字符為0~9
  • 除空白區外的區域和字符都采用二進制編碼表示,1表示bar(黑條),0表示space(白條)
  • 起始符,終止符編碼為101,分隔符編碼為01010
  • 0~9每種字符有3種編碼方式,AB為左側數據奇偶編碼,C為右側數據偶編碼

Python識別快遞條形碼及Tesseract-OCR使用詳解_第2張圖片

  • 左側數據的奇偶性由前置符決定(就是說,第一個支付是幾就按下面的排列開始)

Python識別快遞條形碼及Tesseract-OCR使用詳解_第3張圖片

還有這么一種理解編碼方法

以寬度為編碼,去掉起始碼,終止碼,中間分隔碼,不管白條還是黑條都算一個編碼,最窄一節為1(最窄的為單位寬度),兩個單位寬度就是2,三單位長度為3,四單位寬度為4

四條(不管黑條還是白條都算條)代表一個數字

四條長度 數字
3211 0
2221 1
2122 2
1411 3
1132 4
1231 5
1114 6
1312 7
1213 8
3112 9

兩種編碼的圖示

Python識別快遞條形碼及Tesseract-OCR使用詳解_第4張圖片

這就代表為 數字 1

校驗

EAN13條形碼一共有13位,最后1位是校驗位,該位是通過前12位按照一定的步驟計算出來的。

如果按照一定的步驟處理識別出的前12位數據,如果計算結果和識別出的結果相等,識別正確;

如果不相等,則重新識別或糾錯再校驗或提示識別失敗。

校驗碼計算方法

以下圖所示的條形碼舉例說明:

條形碼的位數起始位為最右一位,即校驗位,檢驗碼計算方法如下:

  • 偶位數數值相加乘3((0+2+0+8+1+9)*3=60)
  • 不含校驗位的奇位數相加(7+4+7+9+3+6=36)
  • 將前兩步的結果相加(60+36=96)
  • 用10減去上一步結果的個位數數值(10-6=4)
  • 上一步結果的個位數即為校驗碼(4)

源碼

            
#創建:2016/01/26
#文件:BarCodeIdentification.py
#作者:moverzp
#功能:識別條形碼
import sys
import cv2

DECODING_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 width

def 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 5

def 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 similarEdge

def 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 barCode

def 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] = 8

def 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 = 1
print '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()
          

第二種編碼的程序

            
#-*- coding:utf-8 -*-
from PIL import Image

def clean(img):
  A = img.load()
  print A
  ss = ''
  for x in xrange(img.size[0]): 
    ss += str(A[x, img.size[1]/2])
  print ss
  ls = []
  while len(ss) > 0: 
    start = ss[0]
    j = 1
    while j < len(ss) and ss[j] == start :
      j += 1
    ls.append(j)
    ss = ss[j:]
  print ls
  return ls
  #print ls
def GetUPC_A(t):
  #print t
  t = t[4:-4]
  print len(t)
  for i in xrange(len(t)):
    t[i] = (t[i] + 1) / 4
  t = t[:24] + t[29:]
  s = ''
  for i in xrange(len(t)):
   s += str(t[i]) 
  upca = ''
  for i in range(0, len(s) / 4):
    n = i * 4
    upca += dic[s[n:n + 4]]   
  print upca


dic = {'3211':'0', '2221':'1', '2122':'2', '1411':'3', '1132':'4', '1231':'5', '1114':'6', '1312':'7', '1213':'8', '3112':'9'}
img = Image.open('7.png') 
GetUPC_A(clean(img))
          

可惜這次遇到的是快遞單上的條形碼,非標準的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 模塊使用

所以此次識別快遞單號,用到三個

  • Tesseract-OCR ――(直接下載一個exe文件一路”next”即可安裝完成)
  • pytesseract模塊――(直接 pip install pytesseract 安裝即可)
  • PIL模塊――(由于我的是win7_64bit的系統,原PIL不支持,所以用pillow模塊,直接pip install pillow即可)

源代碼

            
#-*- coding:utf-8 -*-
from PIL import Image
import pytesseract
import time

start = time.clock()#開始計時
#---------主要代碼------------
im = Image.open('66.png')
code = pytesseract.image_to_string(im)
print u'驗證碼:' + str(code)
#---------------------------------
end = time.clock()#結束計時

print u'運行時間:' + str(end-start)
          

有坑

在有 Git Bash調試時遇到了

            
Traceback (most recent call last):
 File "111.py", line 10, in 
            
              
  print u'驗證碼:' + str(code)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
            
          

這一看就有事編碼的坑了,我用的是python2.7 估計生3就沒沒坑了

但目前還是要解決這問題,對于這編碼的問題有兩種解決方法:

1.一個解決的方案在程序中加入以下代碼:

            
import sys
reload(sys)
sys.setdefaultencoding('utf8')
          

2.是在python的Lib\site-packages文件夾下新建一個sitecustomize.py,內容為:

            
# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
          

此時重啟python解釋器,執行sys.getdefaultencoding(),發現編碼已經被設置為utf8的了,多次重啟之后,效果相同,這是因為系統在python啟動的時候,自行調用該文件,設置系統的默認編碼,而不需要每次都手動的加上解決代碼,屬于一勞永逸的解決方法。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲 欧美 另类 天天更新影院 | 成人性a激情免费视频 | 成人久久伊人精品伊人 | 四虎成人免费影院网址 | 国产精品免费一级在线观看 | 老司机成人午夜精品福利视频 | 日韩欧美毛片免费看播放 | 亚洲欧美日韩久久一区 | 国产欧美另类第一页 | 美女视频黄的全i免费 | 分分操这里只有精品 | 四虎永久精品免费观看 | 毛片视频免费 | 天天操穴 | 日本精高清区一 | 亚洲美女视频在线观看 | 伊人免费网 | 日本精品一区二区三本中文 | 2020国产成人精品视频人 | 一区二区三区精品国产欧美 | 四虎影院永久在线 | 日本精品欧洲www | 亚洲精品在线观看91 | 久久久午夜影院 | 久久久久久久久久久福利观看 | 天天干夜夜夜操 | 狠狠色噜噜狠狠狠狠2018 | 俺来也欧美亚洲a∨在线 | 国产亚洲精品国产福利在线观看 | 麻豆国产精品免费视频 | 亚洲综合色视频 | 久久一区二区三区精品 | 四虎影在线永久免费观看 | 国产香蕉视频在线播放 | 一本清高清dvd日本播放器 | 手机在线一区二区三区 | 97狠狠操| 久久精品国产99国产精品澳门 | 99久久成人国产精品免费 | 国产精品视频男人的天堂 | 色噜噜狠狠色综合免费视频 |