据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_())
测试图像:
实验结果: