據code128編碼的規則:1、2、3、4黑白相間,寬度不同。數據起始符:211232,數據終止符:2331112,中間六位爲數據00-99,有對應的編碼。如果通過圖像識別出編碼,我們需要黑白框的寬度,判斷數據是否有效需要根據起始符和終止符確定。
如果確定每一個Code128碼框的寬度,首先需要對圖像進行矯正,然後如果圖像是非常清晰的化,簡單的可以直接使用矩形框選確定每一個黑色框的位置大小,再推斷出白色框的位置大小,如果圖像數據過於模糊,且用投影定位矩形框選等難以切割,則可以使用統計的方法進行識別。
"""Code128編碼字典Code128C轉Code128A"""
code128={"00":'sp',"01":'!',"02":'"',"03":'#',"04":'$',"05":'%',"06":'&',"07":'...',"08":'(',"09":')',
"10":'*',"11":'+',"12":',',"13":'-',"14":'.',"15":'/',"16":'0',"17":'1',"18":'2',"19":'3',
"20":'4',"21":'5',"22":'6',"23":'7',"24":'8',"25":'9',"26":':',"27":';',"28":'<',"29":'=',
"30":'>',"31":'?',"32":'@',"33":'A',"34":'B',"35":'C',"36":'D',"37":'E',"38":'F',"39":'G',
"40":'H',"41":'I',"42":'J',"43":'K',"44":'L',"45":'M',"46":'N',"47":'O',"48":'P',"49":'Q',
"50":'R',"51":'S',"52":'T',"53":'U',"54":'V',"55":'W',"56":'X',"57":'Y',"58":'Z',"59":'[',
"60":"\\","61":']',"62":'^',"63":'_',"64":'NUL',"65":'SOH',"66":'STX',"67":'ETX',"68":'EOT',"69":'ENQ',
"70":'ACK',"71":'BEL',"72":'BS',"73":'HT',"74":'LF',"75":'VT',"76":'FF',"77":'CR',"78":'SO',"79":'SI',
"80":'DLE',"81":'DC1',"82":'DC2',"83":'DC3',"84":'DC4',"85":'NAK',"86":'SYN',"87":'ETB',"88":'CAN',"89":'EM',
"90":'SUB',"91":'ESC',"92":'FS',"93":'GS',"94":'RS',"95":'US',"96":'FNC3',"97":'FNC2',"98":'SHIFT',"99":'CodeC',
"CodeB":'CodeB',"CodeA":'FNC4',"FNC1":'FNC1'}
"""Code128編碼字典轉Code128C"""
Code={'212222': '00', '222122': '01', '222221': '02', '121223': '03', '121322': '04', '131222': '05',
'122213': '06', '122312': '07', '132212': '08', '221213': '09', '221312': '10', '231212': '11',
'112232': '12', '122132': '13', '122231': '14', '113222': '15', '123122': '16', '123221': '17',
'223211': '18', '221132': '19', '221231': '20', '213212': '21', '223112': '22', '312131': '23',
'311222': '24', '321122': '25', '321221': '26', '312212': '27', '322112': '28', '322211': '29',
'212123': '30', '212321': '31', '232121': '32', '111323': '33', '131123': '34', '131321': '35',
'112313': '36', '132113': '37', '132311': '38', '211313': '39', '231113': '40', '231311': '41',
'112133': '42', '112331': '43', '132131': '44', '113123': '45', '113321': '46', '133121': '47',
'313121': '48', '211331': '49', '231131': '50', '213113': '51', '213311': '52', '213131': '53',
'311123': '54', '311321': '55', '331121': '56', '312113': '57', '312311': '58', '332111': '59',
'314111': '60', '221411': '61', '431111': '62', '111224': '63', '111422': '64', '121124': '65',
'121421': '66', '141122': '67', '141221': '68', '112214': '69', '112412': '70', '122114': '71',
'122411': '72', '142112': '73', '142211': '74', '241211': '75', '221114': '76', '413111': '77',
'241112': '78', '134111': '79', '111242': '80', '121142': '81', '121241': '82', '114212': '83',
'124112': '84', '124211': '85', '411212': '86', '421112': '87', '421211': '88', '212131': '89',
'214121': '90', '412121': '91', '111143': '92', '111341': '93', '131141': '94', '114113': '95',
'114311': '96', '411113': '97', '411311': '98', '113141': '99', "211412":'StartA',"211214":'StartB',
"211232":'StartC',"2331112":'Stop',"114131":'CodeB',"311141":'CodeA',"411131":'FNC1'}
基於統計方法實現Code128碼實現源碼:
#!usr/bin/python3
# -*- coding:utf-8 -*-
# author:SingWeek
import cv2
from para import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys, os
import matplotlib.pyplot as plt
def ImgRead(file):
"""
處理圖像讀取
:param file:讀取的圖像路徑
:return:
"""
img=cv2.imread(file, 0)
return img
def CalcHist(img):
"""
將圖像沿着編碼方向投影
:param img:
:return: 投影后的波形數值
"""
w, h = img.shape[:2] # 180,800
print(w,h)
lists = []
for i in range(h): # 像素值統計
tmp = 0
for j in range(w):
tmp += img[j][i]
lists.append(tmp)
return lists
def Split(lists,means = 16100):
"""
對投影后的分段波形值進行切分
:param lists: 投影后的分段波形數值
:param means:切分值
:return:
"""
result=[]
Flags = False
Whitenum = 0
Blacknum = 0
for i in lists:
if i > means: # 白色點
if Flags == True:
result.append(Blacknum)
Whitenum = 0
Blacknum = 0
Flags = False
Whitenum += 1
else: # 黑色點
if Flags == False:
result.append(Whitenum)
Whitenum = 0
Blacknum = 0
Blacknum += 1
Flags = True
return result
def Calc(startC,a1,a2,a3):
tmpdata=''
for i in range(len(startC)):
j=int(startC[i])
if j<a1*2:#最小
tmpdata += '1'
elif j>a2*1.8:#最大
tmpdata += '4'
else:
if j<a2:
#根據疑似2標籤的值判斷其周圍的數據確定是1還是2
if i<len(startC)-1:
tmp = int(startC[i + 1])
if tmp * 1.8 < j:
tmpdata += '1'
else:
if i>0:
tmp=int(startC[i-1])
if tmp * 1.8 < j:
tmpdata += '1'
else:
if tmp>a2:
tmpdata += '3'
else:
tmpdata += '2'
else:
tmpdata += '2'
else:
tmpdata += '2'
else:
if j>=a3:
tmpdata += '3'
else:#對於大於疑似標籤2的值,可能是3還是2做進一步判斷
if i<len(startC)-1:
tmp=int(startC[i+1])
if tmp*1.8<j:
if tmp<=a1:
tmpdata += '2'
else:
tmpdata += '3'
else:
if i<len(startC)-1:
tmp = int(startC[i + 1])
if tmp * 1.8 < j:
tmpdata += '3'
else:
tmpdata += '2'
else:
tmpdata += '2'
else:
tmpdata += '2'
print(i, tmpdata)
print(tmpdata)
return tmpdata
def CodeList(result,type='codec'):
"""
閾值切分後的波形值
:param result:
:param type:返回的值類型
:return:
"""
result = result[1:] # 去除最開始的空白值
startC = result[:6] # 其始值
data = result[6:-7] # 終止值
endC = result[-7:] # 數據
if len(data) % 6 == 0: # 數據位校驗
print("OK!")
sum1list = [startC[1], startC[2], endC[3], endC[4], endC[5]]
sum2list = [startC[0], startC[3], startC[5], endC[0], endC[6]]
sum3list = [startC[4], endC[1], endC[2]]
a1, b1 = divmod(sum(sum1list), 5)
a2, b2 = divmod(sum(sum2list), 5)
a3, b3 = divmod(sum(sum3list), 3)
start=Calc(startC, a1, a2, a3)
end=Calc(endC, a1, a2, a3)
DataFlags=False
try:
if Code[start]=="StartC" and Code[end]=="Stop":
print("校驗成功")
DataFlags = True
else:
print("校驗失敗")
return start+"-"+end
except:
print("校驗失敗")
return start + "-" + end
if DataFlags==True:
codevalue = []
for i in range(0, len(data), 6):
tmpdata = Calc(data[i:i + 6], a1, a2, a3)
codevalue.append(Code[tmpdata])
if type=='codec':
tmp=''
for i in codevalue:
tmp+=i
return tmp
else:
tmp=[]
for i in codevalue:
tmp.append(code128[i])
print("******************",tmp)
return tmp
else:
print("Wrong!")
return "Data length wrong!"
def Get_Threshold(lists):
"""
自動切割閾值獲取
:param lists:
:return:
"""
means=sum(lists)/len(lists)
s=False
e=False
num=0
up=[]
down=[]
upsum=[]
downsum=[]
upnum=0
downnum=0
for i in range(len(lists)):
if lists[i]<means:
s=True
downsum.append(int(lists[i]))
downnum+=1
else:
e=True
upsum.append(int(lists[i]))
upnum+=1
if s==True and e==True:
num+=1
if num%2==0:
down.append(max(downsum))
else:
up.append(max(upsum))
s = False
e = False
upsum = []
downsum = []
upnum = 0
downnum = 0
up.append(max(upsum))
# print(means)
# print(up)
# print(down)
# print(max(down)-min(up))
# print(min(up)-min(down))
if max(down)-min(up)<0:
# print(max(down))
return max(down)
result=[]
try:
for i in range(len(up)):
if up[i]-max(down)>min(up)-min(down):#踢掉臨近切分值
result.append(up[i])
print(result,min(result),min(result)-(min(up)-min(down))/10)
return min(result)-(min(up)-min(down))/10
except:
return max(down)
class MyWindow(QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.setGeometry(300, 300, 200, 300)
self.setWindowTitle('Code128')
self.startbtn=QPushButton("運行",self)
self.typelabel=QLineEdit("codec",self)
self.labelshow=QLineEdit("顯示結果",self)
self.thre=QLineEdit("0",self)
self.startbtn.setGeometry(20, 20, 160, 50)
self.typelabel.setGeometry(20, 90, 160, 50)
self.thre.setGeometry(20, 140, 160, 50)
self.labelshow.setGeometry(20, 190, 160, 50)
self.show()
self.startbtn.clicked.connect(self.StartRun)
def StartRun(self):
self.file = QFileDialog.getOpenFileNames(None, "", "", "")[0]
type=self.typelabel.text()
data_thread = UpdateData(self.file,type,self.labelshow,int(self.thre.text()))
data_thread.run()
self.labelshow.setText("請重新選擇!")
class UpdateData(QThread):
"""界面和 運行相分離,通過信號與槽來進行參數傳遞"""
def __init__(self, file,type,label,thredata,parent=None):
super(UpdateData, self).__init__(parent)
self.file = file[0]
self.type=type
self.label=label
self.thredata=thredata
def run(self):
img=ImgRead(self.file)
# cv2.imshow("img",img)
lists=CalcHist(img)
print("----")
if self.thredata==0:
print("*****")
thre0=int(Get_Threshold(lists))
print(thre0)
result=Split(lists,thre0)
else:
result=Split(lists,self.thredata)
print("切分後的數組:",result)
out=CodeList(result,self.type)
self.label.setText(str(out))
plt.plot(lists)
plt.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
mywindow = MyWindow()
mywindow.show()
app.exit(app.exec_())
測試圖像:
實驗結果: