进行车牌识别包含车牌检测+车牌识别
车牌检测:图像分割+特征提取
车牌识别:对检测到的车牌进行内容识别
车牌主要包括以下几种:
蓝牌白字:普通小型车(其中包括政府机关专用号段、政法部门警车以外的行政用车)的牌照
黄牌黑字:大型车辆、摩托车、驾校教练车牌照
黑牌白字:涉外车辆牌照,式样和蓝牌基本相同
白牌:政法部门(公安、法院、检察院、国安、司法)警车、武警部队车辆、解放军军车的牌照都是白牌
警车:公安警车的牌照样式为[某·A1234警],除“警”为红字外其他的都是黑字,一共4位数字,含义与普通牌照相同
车牌检测定位的方法:
对于边缘图像,如果车牌在图像中占得比例不是很小,普通的差分或者全局二值化就可以达到很好的效果;
对于高清图像或场景很复杂的情况,车牌所占比例很小,或车牌处于较暗的地方,而整个场景很亮,此时差分不会得到很好的效果,可以对图像进行对比度增强,但对比度增强可能导致噪声点特别多,导致车牌区域检测不到边缘。
检测可以用到的特征:
颜色特征
每种车牌的底色具有各自特殊的RGB值,例如程序中使用的蓝底车牌的典型RGB值为 R = 28,G = 63, B = 138;
当RGB值接近时则认为可能是车牌,将该点像素赋值为255,否则0;利用颜色特征可以获取二值图像,可以去除大部分的其他物体,但是会有很多的干扰。
大小特征
对二值图像进行膨胀处理和腐蚀处理之后,可以去掉很小的噪点。对于灰度图获取轮廓边缘,轮廓具有一定的面积。车牌应该具有一定的大小,如果面积过小则认为不是车牌。此法可以去除大部分的小面积的干扰物。
颜色特征和大小特征是初选。形状特征是精选。
形状特征
矩形度:提取轮廓之后,轮廓包围的面积和轮廓最小外接矩形的面积之比称为矩形度,值越接近1,则是矩形的概率越大。
长宽比:正常车牌的长宽比为3:1,最小外接矩形的长宽比越接近1则认为是车牌的概率最大。
如果三个筛选条件都符合,则是车牌的概率非常大。
import cv2
import numpy as np
import math
""" 输入图像归一化 """
def stretch(img):
max = float(img.max())
min = float(img.min())
for i in range(img.shape[0]):
for j in range(img.shape[1]):
img[i, j] = (255 / (max - min)) * img[i, j] - (255 * min) / (max - min)
return img
def dobinaryzation(img):
max = float(img.max())
min = float(img.min())
x = max - ((max - min) / 2)
ret, thresholdimg = cv2.threshold(img, x, 255, cv2.THRESH_BINARY)
return thresholdimg
def find_retangle(contour):
y, x = [], []
for p in contour:
y.append(p[0][0])
x.append(p[0][1])
return [min(y), min(x), max(y), max(x)]
def locate_license(img, orgimg):
img, contours, hierachy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# 找到最大的三个区域
blocks = []
for c in contours:
# 找出轮廓的左上和右下点,计算出其面积和长宽比
r = find_retangle(c)
a = (r[2] - r[0]) * (r[3] - r[1])
s = (r[2] - r[0]) / (r[3] - r[1])
blocks.append([r, a, s])
# 选出面积最大的3个区域
blocks = sorted(blocks, key=lambda b: b[2])[-3:]
# 使用颜色识别判断出最像车牌的区域
maxweight, maxinedx = 0, -1
for i in range(len(blocks)):
b = orgimg[blocks[i][0][1]:blocks[i][0][3], blocks[i][0][0]:blocks[i][0][2]]
# RGB 转HSV
hsv = cv2.cvtColor(b, cv2.COLOR_BGR2HSV)
# 蓝色车牌范围
lower = np.array([100, 50, 50])
upper = np.array([140, 255, 255])
# 根据阈值构建掩膜
mask = cv2.inRange(hsv, lower, upper)
# 统计权值
w1 = 0
for m in mask:
w1 += m / 255
w2 = 0
for w in w1:
w2 += w
# 选出最大权值的区域
if w2 > maxweight:
maxindex = i
maxweight = w2
return blocks[maxindex][0]
def find_license(img):
'''预处理'''
# 压缩图像
a = 400 * img.shape[0] / img.shape[1]
a = int(a)
img = cv2.resize(img, (400, a))
cv2.imshow('img',img)
cv2.waitKey()
# RGB转灰色
grayimg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('grayimg', grayimg)
cv2.waitKey()
# 灰度拉伸
stretchedimg = stretch(grayimg)
cv2.imshow('stretchedimg', stretchedimg)
cv2.waitKey()
# 进行开运算,用来去除噪声
r = 16
h = w = r * 2 + 1
kernel = np.zeros((h, w), dtype=np.uint8)
cv2.circle(kernel, (r, r), r, 1, -1)
openingimg = cv2.morphologyEx(stretchedimg, cv2.MORPH_OPEN, kernel)
cv2.imshow('openingimg', openingimg)
cv2.waitKey()
strtimg = cv2.absdiff(stretchedimg, openingimg)
cv2.imshow('strtimg', strtimg)
cv2.waitKey()
# 图像二值化
binaryimg = dobinaryzation(strtimg)
cv2.imshow('binaryimg', binaryimg)
cv2.waitKey()
# Canny算子进行边缘检测
cannyimg = cv2.Canny(binaryimg, binaryimg.shape[0], binaryimg.shape[1])
cv2.imshow('cannyimg', cannyimg)
cv2.waitKey()
'''消除小区域,连通大区域'''
# 进行闭运算
kernel = np.ones((5, 19), np.uint8)
closingimg = cv2.morphologyEx(cannyimg, cv2.MORPH_CLOSE, kernel)
cv2.imshow('closingimg', closingimg)
cv2.waitKey()
# 进行开运算
openingimg = cv2.morphologyEx(closingimg, cv2.MORPH_OPEN, kernel)
cv2.imshow('openingimg', openingimg)
cv2.waitKey()
# 再次进行开运算
kernel = np.ones((11, 5), np.uint8)
openingimg = cv2.morphologyEx(openingimg, cv2.MORPH_OPEN, kernel)
cv2.imshow('openingimg', openingimg)
cv2.waitKey()
# 消除小区域,定位车牌位置
rect = locate_license(openingimg, img)
return rect, img
if __name__ == '__main__':
orgimg = cv2.imread('car3.jpg')
rect, img = find_license(orgimg)
cv2.rectangle(img, (rect[0], rect[1]), (rect[2], rect[3]), (0, 255, 0), 2)
cv2.imshow('img', img)
cv2.waitKey()
cv2.destroyAllWindows()