车牌识别项目
不经常上线,既然有人想要代码,现在我将它发出来,不过需要你们下载,具体下载方法,我想你们都懂得。
https://download.csdn.net/download/weixin_43648821/11423543
本博客关于深度学习完成后,做的有一个小项目,基本已完成。环境配置:Win7、Python3.7、Opencv4.10。作本项目,一是为总结,二是方便以后的回顾。
车牌图像处理原理
一、是读取图像,对图像进行预处理,包括(具有先后顺序):压缩图像、转换为灰度图像、灰度拉伸、开运算(去噪声)、将灰度图像和开运算后图像取差分图、整张图像二值化、canny边缘检测、闭运算、开运算、再次开运算(这三步是为了保留车牌区域,并消除其他区域)、定位车牌位置(找轮廓、画轮廓、取前三个轮廓进行排序、找出最大的区域);
二、是框处车牌号;
三、分割车牌号和背景,分割包括:创建掩膜、创建背景和前景、分割;
四、将分割出来的车牌进行二值化,生成黑白图像;
五、分割出车牌号码中的文字、数字和字母,放入特定的文件夹;
六、对分割出来的文字、数字和字母图像尺寸进行处理,以方便后面测试。
测试所用图像
下面是相关代码
主函数
def carimg_make(img):
# 预处理图像
rect, afterimg = preprocessing(img) # 其实包括了对车牌定位
print("rect:", rect)
# 框出车牌
cv2.rectangle(afterimg, (rect[0], rect[1]), (rect[2], rect[3]), (0, 255, 0), 2)
cv2.imshow('afterimg1', afterimg)
# 分割车牌与背景
cutimg = cut_license(afterimg, rect)
cv2.imshow('cutimg', cutimg)
# 二值化生成黑白图
thresh = lice_binarization(cutimg)
cv2.imshow('thresh', thresh)
cv2.waitKey(0)
# 分割字符
'''
判断底色和字色
'''
# 记录黑白像素总和
white = [] # 记录每一列的白色像素总和
black = [] # 记录每一列的黑色像素总和
height = thresh.shape[0] # 263
width = thresh.shape[1] # 400
white_max = 0 # 仅保存每列,取列中白色最多的像素总数
black_max = 0 # 仅保存每列,取列中黑色最多的像素总数
# 计算每一列的黑白像素总和
for i in range(width):
line_white = 0 # 这一列白色总数
line_black = 0 # 这一列黑色总数
for j in range(height):
if thresh[j][i] == 255:
line_white += 1
if thresh[j][i] == 0:
line_black += 1
white_max = max(white_max, line_white)
black_max = max(black_max, line_black)
white.append(line_white)
black.append(line_black)
print('white_max', white_max)
print('black_max', black_max)
# arg为true表示黑底白字,False为白底黑字
arg = True
if black_max < white_max:
arg = False
# 分割车牌的数字
n = 1
start = 1
end = 2
s_width = 28
s_height = 28
temp = 1
while n < width - 2:
n += 1
# 判断是白底黑字还是黑底白字 0.05参数对应上面的0.95 可作调整
if (white[n] if arg else black[n]) > (0.05 * white_max if arg else 0.05 * black_max):#这点没有理解透彻
start = n
end = find_end(start, arg, black, white, width, black_max, white_max)
n = end
print("start" + str(start))
print("end" + str(end))
# 思路就是从左开始检测匹配字符,若宽度(end - start)小与20则认为是左侧白条 pass掉 继续向右识别,否则说明是
# 省份简称,剪切,压缩 保存,还有一个当后五位有数字 1 时,他的宽度也是很窄的,所以就直接认为是数字 1 不需要再
# 做预测了(不然很窄的 1 截切 压缩后宽度是被拉伸的),shutil.copy()函数是当检测
# 到这个所谓的 1 时,从样本库中拷贝一张 1 的图片给当前temp下标下的字符
# if end - start > 5:
# print("end - start" + str(end - start))
if end - start > 5:
cj = thresh[1:height, start:end]
print("result/%s.jpg" % (n))
cv2.imwrite('img/{0}.bmp'.format(n), cj)
#对分割出的数字、字母进行裁剪
b_img = cv2.resize(cj, None, fx=5, fy=3)
contours, hierarchy = cv2.findContours(b_img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
block = []
for c in contours:
# 找出轮廓的左上点和右下点,由此计算它的面积和长度比
r = find_rectangle(c) # 里面是轮廓的左上点和右下点
a = (r[2] - r[0]) * (r[3] - r[1]) # 面积
s = (r[2] - r[0]) / (r[3] - r[1]) # 长度比
block.append([c, r, a, s])
block1 = sorted(block, key=lambda block: block[2])[-1:]
# rect = cv2.minAreaRect(block2)
# box1 = np.int0(cv2.boxPoints(rect))
box = block1[0][1]
y_mia = box[0] # y_mia
x_min = box[1] # x_min
y_max = box[2] # y_max
x_max = box[3] # x_max
cropImg = b_img[x_min:x_max, y_mia:y_max] # crop the image
cv2.imwrite('img_test/{0}.bmp'.format(n), cropImg)
cv2.imshow('cutlicense', cj)
cv2.imshow("charecter",cropImg)