多年前,使用写的一个车牌识别程序。里面需要用到CV2进行图像采集、分割处理,用python编写,深度学习识别部分可以自己训练或者采用各种云上提供的人工智能服务。程序仅仅涉及主要流程处理,没有界面,只能处理蓝牌车和绿牌车,对于更多的车牌类型也没有去研究,仅仅在于摸清楚原理。另外,训练深度学习,采用笔记本电脑,确实太费时间,这帖子不写。
主要流程
# 1、读取图片
imgread = cv2.imread('mytest\img2.jpg')
frame=location_demo(imgread) #定位车牌,返回车牌
cv2.imwrite("img70.jpg",frame) #写入车牌文件
cv2.imshow("vehicle plate location", frame)#显示车牌图片
cv2.waitKey(0) #接收按键继续
my_cut("img70.jpg") #分割车牌后,单色化处理
#rec_dig_letter('predict')#自己训练的识别模型,下面用别人的
cn=Ocr() #初始化人工智能文字识别
res=cn.ocr("img80.jpg") #通过人工智能文字识别程序识别切割出的车牌
print(res) #打印车牌号码
cv2.destroyAllWindows()
定位车牌
定位车牌主要通过设置色彩空间范围,查找到车牌响应色彩的多边形,通过多边形的面积,查找出车牌。因为一定距离,车牌的面积是相对稳定的。最后画出车牌轮廓,用于调试;剪裁出图片,可以给后续程序使用。
def location_demo(img):
image = cv2.resize(img,(1200,1200)) #对读取图片做大小调整
lower_blue = np.array([100, 80, 60]) #设置蓝色和绿色色彩空间范围
upper_blue = np.array([130, 255, 255])
lower_green = np.array([30, 100, 100])
upper_green = np.array([78, 255, 255])
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) #转换色彩空间BGR转HSV
mask_blue = cv2.inRange(hsv, lower_blue, upper_blue) #设置mask
mask_green = cv2.inRange(hsv, lower_green, upper_green)
output = cv2.bitwise_and(hsv, hsv, mask=mask_blue)#+mask_green ) #蓝色的车牌,采用蓝色mask
Matrix = np.ones((20, 20), np.uint8)
cv2.imshow('img_edge2', output)
cv2.waitKey(0)
img_edge1 = cv2.morphologyEx(output, cv2.MORPH_CLOSE, Matrix)
cv2.imshow('img_edge2', img_edge1)
cv2.waitKey(0)
img_edge2 = cv2.morphologyEx(img_edge1, cv2.MORPH_OPEN, Matrix)
cv2.imshow('img_edge2',img_edge2)
cv2.waitKey(0)
# 根据阈值找到对应颜色
img_edge3 = np.clip(img_edge2, 0, 255) # 归一化也行
contours , hierarchy = cv2.findContours(img_edge3[...,0],cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#对图像进行轮廓检测
print(contours)
cv2.imshow('img_edge2', img_edge3)
cv2.waitKey(0)
for i in range(0, len(contours)): #对所有检测到的轮廓进行按(车牌)面积筛选
cnt = contours[i]
area = cv2.contourArea(cnt)
#求轮廓面积
if area >3000 :
rect=cv2.minAreaRect(cnt)
#对所选取的面积求矩形最小面积
box = cv2.boxPoints(rect)
#矩形点信息提取
box = np.int0(box)
print(area)
print(box)
#个人爱好,观察下面积大小- -!
#拷贝出车牌
cj =cut1(image,box)
cv2.imshow("vehicle plate location", cj)
cv2.waitKey(0)
image = cv2.drawContours(image, [box], -1, (0, 255, ), 4)
cv2.imshow("vehicle plate location", image)
cv2.waitKey(0)
#矩形绘画'''
return cj
分割车牌
def my_cut(img_name):
loc=[40,80,96,136,176,216,256,296] #分割车牌字母位置
img = cv2.imread(img_name) #读取分割图片
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) #转换色彩为灰度图像
img_gray = cv2.GaussianBlur(img_gray, (3,3),0) #做滤波
immean=cv2.mean(img) #求各分量均值,目的是什么车牌
img_gray2= cv2.equalizeHist(img_gray) #均衡图像
cv2.imshow('gray2',img_gray2) #用于调试显示,看中间处理结果
cv2.waitKey(0)
if immean[0]>immean[1]: #绿色车牌和蓝色刚好相反
binary_threshold = 190 #设置阈值
else:
binary_threshold = 80
# 2、按照前面设定阀值,将灰度图二值化
img_thre = img_gray2
cv2.threshold(img_gray2, binary_threshold, 255, cv2.THRESH_BINARY_INV, img_thre)
cv2.imshow('lumk', img_thre) #再看看处理结果
cv2.waitKey(0)
height = img_thre.shape[0]
width = img_thre.shape[1]
img_thre = cv2.resize(img_thre, (300, 80)) #改变图像大小到固定值
cv2.imwrite('img80.jpg', img_thre) #这是已经处理好的黑白色车牌
#下面是把车牌每一个字母分割开来,可以自己训练字符集识别
old=0
ind=1
for i in loc:
cj = img_thre[1:80, old:i]
cv2.imwrite('d:\\img\\ii' + format(ind) + '.bmp', cj) # 此句是输出每个字符,当时未输出直接看的时候因为刷新问题,解决好久,后来发现只是显示刷新的问题
image3 = cv2.imread('d:\\img\\ii' + format(ind) + '.bmp', cv2.IMREAD_GRAYSCALE)
image3 = cv2.resize(image3, (32, 40))
cv2.bitwise_not(image3, image3)
cv2.imwrite('d:\\img\\ii' + format(ind) + '.bmp', image3)
old=i
ind=ind+1
cv2.imshow('cutChar', cj)
cv2.waitKey(0)
# 4、分割字符
'''
white = [] # 记录每一列的白色像素总和
black = [] # 记录每一列的黑色像素总和
height = img_thre.shape[0]
width = img_thre.shape[1]
print(width, height)
white_max = 0 # 仅保存每列,取列中白色最多的像素总数
black_max = 0 # 仅保存每列,取列中黑色最多的像素总数
# 循环计算每一列的黑白色像素总和
for i in range(width):
w_count = 0 # 这一列白色总数
b_count = 0 # 这一列黑色总数
for j in range(height):
if img_thre[j][i] == 255:
w_count += 1
else:
b_count += 1
white_max = max(white_max, w_count)
black_max = max(black_max, b_count)
white.append(w_count)
black.append(b_count)
识别车牌
识别车牌字母的两种方式,采用自己训练的车牌识别程序,我训练了一周,而且数据获取,太麻烦,太费事,最终只实现了字母和数字识别,汉字没有做。
最终,用了网络上的识别程序实现,识别率非常高,完美!
过程输出
原始图,采用手机拍摄,由于车牌是别人的,所以改了号码。
这是定位到的图片位置
下面是根据图片位置裁剪和变换的结果。
最后是识别的输出。