为了进行车牌识别,需要以下几个基本的步骤:
1、牌照字符分割,把牌照中的字符分割出来;
2、牌照字符识别,把分割好的字符进行识别,最终组成牌照号码。
车牌识别过程中,牌照颜色的识别依据算法不同,可能在上述不同步骤实现,通常与车牌识别互相配合、互相验证。
牌照字符分割
完成牌照区域的定位后,再将牌照区域分割成单个字符,然后进行识别。字符分割一般采用垂直投影法。由于字符在垂直方向上的投影必然在字符间或字符内的间隙处取得局部最小值的附近,并且这个位置应满足牌照的字符书写格式、字符、尺寸限制和一些其他条件。利用垂直投影法对复杂环境下的汽车图像中的字符分割有较好的效果。
# 对车牌图片进行处理,分割出车牌中的每一个字符并保存
license_plate = cv2.imread('车牌/1.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
characters = []
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)
characters.append(ndarray)
牌照字符识别,把分割好的字符进行识别,最终组成牌照号码。
首先应该创建字符字典(图像列表)
# 生成车牌字符图像列表
data_path = './data'
character_folders = os.listdir(data_path)
label = 0
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 == 'data18414':
continue
print(character_folder + " " + str(label))
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
牌照字符识别方法主要有基于模板匹配算法和基于人工神经网络算法。基于模板匹配算法首先将分割后的字符二值化并将其尺寸大小缩放为字符数据库中模板的大小,然后与所有的模板进行匹配,选择最佳匹配作为结果。基于人工神经网络的算法有两种:一种是先对字符进行特征提取,然后用所获得特征来训练神经网络分配器;另一种方法是直接把图像输入网络,由网络自动实现特征提取直至识别出结果。
这里选择搭建leNet5卷积神经网络,用于识别车牌的每一个字符
# 搭建leNet5卷积神经网络,用于识别车牌的每一个字符
def convolutional_neural_network(input):
#卷积层,卷积核大小为3*3,步长是1,一共有32个卷积核
conv_1=fluid.layers.conv2d(input=input,num_filters=50,filter_size=5,stride=1)
#池化层,池化核大小为2*2,步长是1,最大池化
pool_1=fluid.layers.pool2d(input=conv_1,pool_size=2,pool_stride=1,pool_type='max')
#第二个卷积层,卷积核大小为3*3,步长1,一共有64个卷积核
conv_2=fluid.layers.conv2d(input=pool_1,num_filters=32,filter_size=3,stride=1)
#第二个池化层,池化核大小是2*2,步长1,最大池化
pool_2=fluid.layers.pool2d(input=conv_2,pool_size=2,pool_stride=1,pool_type='max')
#以softmax为激活函数的全连接输出层,大小为label的大小
#softmax一般用于多分类问题最后一层输出层的激活函数,作用是对输出归一化,这种情况下一般损失函数使用交叉熵
fc=fluid.layers.fc(input=pool_2,size=65,act='softmax')
return fc
# 开始训练,20个pass
for pass_id in range(20):
for batch_id, data in enumerate(train_reader()):
train_cost, train_acc = exe.run(program=fluid.default_main_program(),
feed=feeder.feed(data),
fetch_list=[avg_cost, accuracy])
if batch_id % 100 == 0:
print('nPass:%d, Batch:%d, Cost:%f, Accuracy:%f' % (pass_id, batch_id, train_cost[0], train_acc[0]))
else:
print('.', end="")
# 每一个pass进行一次测试
test_costs = []
test_accs = []
for batch_id, data in enumerate(test_reader()):
test_cost, test_acc = exe.run(program=test_program,
feed=feeder.feed(data),
fetch_list=[avg_cost, accuracy])
test_costs.append(test_cost[0])
test_accs.append(test_acc[0])
test_cost = sum(test_costs) / len(test_costs)
test_acc = sum(test_accs) / len(test_accs)
print('nTest:%d, Cost:%f, Accuracy:%f' % (pass_id, test_cost, test_acc))
fluid.io.save_inference_model(dirname='./model', feeded_var_names=['image'], target_vars=[result], executor=exe)
模型训练完成之后,将要预测的图片事先准备好
对图片进行预处理:
# 对字符图片进行预处理
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
执行预测
执行预测
labels = []
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)
result = exe.run(program=infer_program,
feed={feeded_var_names[0]:infer_imgs},
fetch_list=target_vars)
labels.append(np.argsort(result)[0][0][-1])
与字典进行比对:
# 将原车牌图片和预测后对结果打印出来
match = {0:'Z', 1:'云', 2:'桂', 3:'G', 4:'E', 5:'2', 6:'甘', 7:'5', 8:'3', 9:'6', 10:'C', 11:'F', 12:'川', 13:'京', 14:'沪', 15:'R', 16:'新',
17:'0', 18:'X', 19:'闽', 20:'4', 21:'J', 22:'湘', 23:'苏', 24:'陕', 25:'藏', 26:'冀', 27:'皖', 28:'青', 29:'K', 30:'渝', 31:'A', 32:'N', 33:'W',
34:'P', 35:'7', 36:'吉', 37:'1', 38:'V', 39:'浙', 40:'D', 41:'豫', 42:'宁', 43:'蒙', 44:'L', 45:'Q', 46:'鲁', 47:'津', 48:'晋', 49:'S', 50:'M',
51:'8', 52:'B', 53:'9', 54:'赣', 55:'琼', 56:'黑', 57:'Y', 58:'贵', 59:'辽', 60:'鄂', 61:'T', 62:'H', 63:'粤', 64:'U'
}
display(Image.open('车牌/1.png'))
print('n车牌识别结果为:',end='')
for i in range(len(labels)):
print(match[labels[i]], end='')
代码已上传至Aistudio
车牌识别 - 百度AI Studio - 一站式AI开发实训平台aistudio.baidu.com