导读1:车牌识别 比一般的分类问题多了一个步骤,即将车牌的7个字符进行分割
导读2:车牌识别 的类别 分为70个
10个数字 0-9
26个英文字母 A-Z
34个省份简称 如min闽、liao辽、gan赣等
emm… 我怎么算的是70呢?教程中的类别数为65啊
问题不大,大家使用的数据集类别是多少就改为多少,文中的类别数都为65
# 查看当前挂载的数据集目录
!ls /home/aistudio/data
# 解压数据集
!unzip -q /home/aistudio/data/data23617/characterData.zip
#导入需要的包
import numpy as np
import paddle as paddle
import paddle.fluid as fluid
from PIL import Image
import cv2
import matplotlib.pyplot as plt
import os
from multiprocessing import cpu_count
from paddle.fluid.dygraph import Pool2D,Conv2D
# from paddle.fluid.dygraph import FC
from paddle.fluid.dygraph import Linear
训练集列表 train_data.list 和 测试集列表test_data.list 比例为9:1
# 生成车牌字符图像列表
data_path = '/home/aistudio/data'
character_folders = os.listdir(data_path)
label = 0
LABEL_temp = {}
if(os.path.exists('./train_data.list')):
os.remove('./train_data.list')
if(os.path.exists('./test_data.list')):
os.remove('./test_data.list')
for character_folder in character_folders:
with open('./train_data.list', 'a') as f_train:
with open('./test_data.list', 'a') as f_test:
if character_folder == '.DS_Store' or character_folder == '.ipynb_checkpoints' or character_folder == 'data23617':
continue
print(character_folder + " " + str(label))
LABEL_temp[str(label)] = character_folder #存储一下标签的对应关系
character_imgs = os.listdir(os.path.join(data_path, character_folder))
for i in range(len(character_imgs)):
if i%10 == 0:
f_test.write(os.path.join(os.path.join(data_path, character_folder), character_imgs[i]) + "\t" + str(label) + '\n')
else:
f_train.write(os.path.join(os.path.join(data_path, character_folder), character_imgs[i]) + "\t" + str(label) + '\n')
label = label + 1
print('图像列表已生成')
train_reader 和 test_reader
# 用上一步生成的图像列表定义车牌字符训练集和测试集的reader
def data_mapper(sample):
img, label = sample
img = paddle.dataset.image.load_image(file=img, is_color=False)
img = img.flatten().astype('float32') / 255.0
return img, label
def data_reader(data_list_path):
def reader():
with open(data_list_path, 'r') as f:
lines = f.readlines()
for line in lines:
img, label = line.split('\t')
yield img, int(label)
return paddle.reader.xmap_readers(data_mapper, reader, cpu_count(), 1024)
# 用于训练的数据提供器
train_reader = paddle.batch(reader=paddle.reader.shuffle(reader=data_reader('./train_data.list'), buf_size=512), batch_size=128)
# 用于测试的数据提供器
test_reader = paddle.batch(reader=data_reader('./test_data.list'), batch_size=128)
大家可以踊跃尝试各种分类网络,如AlexNet、VGGNet、ResNet等
全连接的最后一个通道改为 类别数 即可
#定义网络
class MyLeNet(fluid.dygraph.Layer):
def __init__(self):
super(MyLeNet,self).__init__()
self.hidden1_1 = Conv2D(1,28,5,1) #(通道数,卷积核个数,卷积核大小) featuremap (20-5+1) 变成 16* 16
self.hidden1_2 = Pool2D(pool_size=2,pool_type='max',pool_stride=1) #采用是取最大值,池化步长可以改 1
self.hidden2_1 = Conv2D(28,32,3,1) #(28,因为上一个卷积核28)
self.hidden2_2 = Pool2D(pool_size=2,pool_type='max',pool_stride=1)
self.hidden3 = Conv2D(32,32,3,1)
self.hidden4 = Linear(32*10*10,65,act='softmax') #转换为全连接层FC,便于分类输出,概率
def forward(self,input): #print x.shape 用于输出参数,辅助理解和观察,便于及时调整参数
x = self.hidden1_1(input)
#print(x.shape)
x = self.hidden1_2(x)
x = self.hidden2_1(x)
x = self.hidden2_2(x)
x = self.hidden3(x)
x = fluid.layers.reshape(x,shape=[-1,32*10*10]) #转换为一维数组
y = self.hidden4(x)
return y
#迭代输出损失函数和精度大小
Iter=0
Iters=[]
all_train_loss=[]
all_train_accs=[]
def draw_train_process(iters,train_loss,train_accs):
title = "training loss/training accs"
plt.title(title,fontsize=24)
plt.xlabel("iter",fontsize=14)
plt.ylabel("loss/acc",fontsize=14)
plt.plot(iters,train_loss,color='red',label='training loss')
plt.plot(iters,train_accs,color='green',label='traning_accs')
plt.legend()
plt.grid()
plt.show()
with fluid.dygraph.guard():
model=MyLeNet() #模型实例化
model.train() #切换到训练模式,该模式下自动搭建反向传播网络,评估模式没有
opt=fluid.optimizer.SGDOptimizer(learning_rate=0.008, parameter_list=model.parameters())#优化器选用SGD随机梯度下降,学习率为0.001.
epochs_num=100 #迭代次数为2
# 学习率 迭代次数 精度
# 0.001 100 0.9436
# 0.005 100 0.9739
# 0.008 100 0.9806 <---
# 0.008 50 0.9481
# 0.008 150 0.9795
for pass_num in range(epochs_num):
for batch_id,data in enumerate(train_reader()):
images=np.array([x[0].reshape(1,20,20) for x in data],np.float32)
labels = np.array([x[1] for x in data]).astype('int64')
labels = labels[:, np.newaxis]
image=fluid.dygraph.to_variable(images)
label=fluid.dygraph.to_variable(labels)
predict=model(image)#预测
loss=fluid.layers.cross_entropy(predict,label)
avg_loss=fluid.layers.mean(loss)#获取loss值
acc=fluid.layers.accuracy(predict,label)#计算精度
if batch_id!=0 and batch_id%50==0:
print("train_pass:{},batch_id:{},train_loss:{},train_acc:{}".format(pass_num,batch_id,avg_loss.numpy(),acc.numpy()))
avg_loss.backward()
opt.minimize(avg_loss)
model.clear_gradients()
fluid.save_dygraph(model.state_dict(),'MyLeNet')#保存模型
'''
train_pass:0,batch_id:50,train_loss:[0.10017446],train_acc:[1.]
train_pass:0,batch_id:100,train_loss:[6.1501627],train_acc:[0.0625]
train_pass:1,batch_id:50,train_loss:[0.19111615],train_acc:[0.96875]
train_pass:1,batch_id:100,train_loss:[1.7530626],train_acc:[0.375]
train_pass:2,batch_id:50,train_loss:[0.05265328],train_acc:[0.984375]
train_pass:2,batch_id:100,train_loss:[1.1673234],train_acc:[0.71875]
train_pass:3,batch_id:50,train_loss:[0.12571864],train_acc:[0.984375]
train_pass:3,batch_id:100,train_loss:[0.9742809],train_acc:[0.7578125]
...
train_pass:98,batch_id:100,train_loss:[0.00573601],train_acc:[1.]
train_pass:99,batch_id:50,train_loss:[0.00053836],train_acc:[1.]
train_pass:99,batch_id:100,train_loss:[0.00423227],train_acc:[1.]
'''
#模型校验
with fluid.dygraph.guard():
accs = []
model=MyLeNet()#模型实例化
model_dict,_=fluid.load_dygraph('MyLeNet')
model.load_dict(model_dict)#加载模型参数
model.eval()#评估模式
for batch_id,data in enumerate(test_reader()):#测试集
images=np.array([x[0].reshape(1,20,20) for x in data],np.float32)
labels = np.array([x[1] for x in data]).astype('int64')
labels = labels[:, np.newaxis]
image=fluid.dygraph.to_variable(images)
label=fluid.dygraph.to_variable(labels)
predict=model(image)#预测
acc=fluid.layers.accuracy(predict,label)
accs.append(acc.numpy()[0])
avg_acc = np.mean(accs)
print(avg_acc)
'''
0.97596157
'''
这步是预处理工作,当获得一张新车牌图片,需进行该步骤:
对车牌图片进行处理,分割出车牌中的每一个字符并保存
# 对车牌图片进行处理,分割出车牌中的每一个字符并保存
license_plate = cv2.imread('./车牌.png')
gray_plate = cv2.cvtColor(license_plate, cv2.COLOR_RGB2GRAY)
ret, binary_plate = cv2.threshold(gray_plate, 175, 255, cv2.THRESH_BINARY)
result = []
for col in range(binary_plate.shape[1]):
result.append(0)
for row in range(binary_plate.shape[0]):
result[col] = result[col] + binary_plate[row][col]/255
character_dict = {}
num = 0
i = 0
while i < len(result):
if result[i] == 0:
i += 1
else:
index = i + 1
while result[index] != 0:
index += 1
character_dict[num] = [i, index-1]
num += 1
i = index
for i in range(8):
if i==2:
continue
padding = (170 - (character_dict[i][1] - character_dict[i][0])) / 2
ndarray = np.pad(binary_plate[:,character_dict[i][0]:character_dict[i][1]], ((0,0), (int(padding), int(padding))), 'constant', constant_values=(0,0))
ndarray = cv2.resize(ndarray, (20,20))
cv2.imwrite('./' + str(i) + '.png', ndarray)
def load_image(path):
img = paddle.dataset.image.load_image(file=path, is_color=False)
img = img.astype('float32')
img = img[np.newaxis, ] / 255.0
return img
#将标签进行转换
print('Label:',LABEL_temp)
match = {'A':'A','B':'B','C':'C','D':'D','E':'E','F':'F','G':'G','H':'H','I':'I','J':'J','K':'K','L':'L','M':'M','N':'N',
'O':'O','P':'P','Q':'Q','R':'R','S':'S','T':'T','U':'U','V':'V','W':'W','X':'X','Y':'Y','Z':'Z',
'yun':'云','cuan':'川','hei':'黑','zhe':'浙','ning':'宁','jin':'津','gan':'赣','hu':'沪','liao':'辽','jl':'吉','qing':'青','zang':'藏',
'e1':'鄂','meng':'蒙','gan1':'甘','qiong':'琼','shan':'陕','min':'闽','su':'苏','xin':'新','wan':'皖','jing':'京','xiang':'湘','gui':'贵',
'yu1':'渝','yu':'豫','ji':'冀','yue':'粤','gui1':'桂','sx':'晋','lu':'鲁',
'0':'0','1':'1','2':'2','3':'3','4':'4','5':'5','6':'6','7':'7','8':'8','9':'9'}
L = 0
LABEL ={}
for V in LABEL_temp.values():
LABEL[str(L)] = match[V]
L += 1
print(LABEL)
'''
Label: {'0': 'G', '1': 'sx', '2': 'S', '3': 'yu', '4': 'gan1', '5': 'jin', '6': '1', '7': 'C', '8': 'D', '9': 'H', '10': 'U', '11': 'M', '12': 'jl', '13': 'B', '14': 'liao', '15': 'e1', '16': 'zhe', '17': 'cuan', '18': 'yun', '19': 'ji', '20': '8', '21': '9', '22': 'Z', '23': 'N', '24': 'min', '25': 'gan', '26': 'lu', '27': 'gui1', '28': '3', '29': 'K', '30': 'wan', '31': 'J', '32': 'Y', '33': '5', '34': 'xiang', '35': 'xin', '36': 'su', '37': 'qing', '38': 'E', '39': 'F', '40': 'L', '41': 'gui', '42': '0', '43': '2', '44': 'hei', '45': 'X', '46': 'W', '47': 'meng', '48': 'shan', '49': 'Q', '50': 'zang', '51': 'yu1', '52': '7', '53': 'P', '54': 'yue', '55': 'hu', '56': 'R', '57': '4', '58': 'ning', '59': 'jing', '60': 'V', '61': 'T', '62': 'qiong', '63': 'A', '64': '6'}
{'0': 'G', '1': '晋', '2': 'S', '3': '豫', '4': '甘', '5': '津', '6': '1', '7': 'C', '8': 'D', '9': 'H', '10': 'U', '11': 'M', '12': '吉', '13': 'B', '14': '辽', '15': '鄂', '16': '浙', '17': '川', '18': '云', '19': '冀', '20': '8', '21': '9', '22': 'Z', '23': 'N', '24': '闽', '25': '赣', '26': '鲁', '27': '桂', '28': '3', '29': 'K', '30': '皖', '31': 'J', '32': 'Y', '33': '5', '34': '湘', '35': '新', '36': '苏', '37': '青', '38': 'E', '39': 'F', '40': 'L', '41': '贵', '42': '0', '43': '2', '44': '黑', '45': 'X', '46': 'W', '47': '蒙', '48': '陕', '49': 'Q', '50': '藏', '51': '渝', '52': '7', '53': 'P', '54': '粤', '55': '沪', '56': 'R', '57': '4', '58': '宁', '59': '京', '60': 'V', '61': 'T', '62': '琼', '63': 'A', '64': '6'}
'''
#构建预测动态图过程
with fluid.dygraph.guard():
model=MyLeNet()#模型实例化
model_dict,_=fluid.load_dygraph('MyLeNet')
model.load_dict(model_dict)#加载模型参数
model.eval()#评估模式
lab=[]
for i in range(8):
if i==2:
continue
infer_imgs = []
infer_imgs.append(load_image('./' + str(i) + '.png'))
infer_imgs = np.array(infer_imgs)
infer_imgs = fluid.dygraph.to_variable(infer_imgs)
result=model(infer_imgs)
lab.append(np.argmax(result.numpy()))
# print(lab)
display(Image.open('./车牌.png'))
print('\n车牌识别结果为:',end='')
for i in range(len(lab)):
print(LABEL[str(lab[i])],end='')
'''
车牌识别结果为:鲁A686EJ
'''