[摘要] 在车牌识别系统中,最重要的内容之一就是车牌定位。本文采用了数字图像处理技术,使用python+opencv及常用的数字图像处理方法对各种情况下的车牌进行定位,主要采用了HSV空间的颜色分割和边缘检测及轮廓检测方法,实验结果表明采用的方法及设计的系统都是非常有效的。
关键词:opencv 车牌定位 python
随着经济的快速发展,人们生活水平日益提高,汽车也变得越来越普遍。但是与此同时也给交通带来了严重问题,如交通堵塞、交通事故等,为了有效的记录监督此类事故,交通运输和交通管理方面的智能化和信息化变得越来越重要,而在智能化交通系统中车牌识别技术占有重要位置,而车牌定位更是车牌识别的关键内容。针对车牌的情况,我成功设计了一套车牌定位系统来用以定位车牌。
该系统主要研究基于python的车牌定位系统,系统主要包括基于颜色的处理、基于边缘的处理和基于轮廓的定位三大核心部分,下面主要介绍这三大部分。
车牌主要由黄色、蓝色、白色等组成,在本系统中只研究黄色和蓝色的车牌。颜色有几种空间,RGB,CMY,HSV,HSL等,RGB颜色空间是基于物体发光定义的(RGB正好对应光的三原色:Red,Green,Blue),CMY颜色空间是基于光反射定义的(CMY对应了绘画中的三原色:Cyan,Magenta,Yellow),HSV、HSL两个颜色空间都是从人视觉的直观反映而提出来的(H是色调,S是饱和度,I是强度)。经过图像的处理及研究,我发现RGB和CMY不利于定位车牌,往往不能通过对颜色三个通道进行限定来消除干扰,所以我采用HSV颜色空间来对图像进行处理,经过图像的处理和观察及网上查阅资料,我发现蓝色的HSV空间值总是在[100,100,50]到[130,255,255]之间,黄色的HSV空间值总是在[15,150,150]到[30,255,255]之间。因此通过取值能够大概的取出车牌的信息,剔除掉大部分的影响因素,除了少部分的车身是蓝色,及周围有蓝色物品之类的没能很好的处理。
基于边缘的检测主要通过中值滤波和sobel算子及图像的形态学运算包括图像的膨胀腐蚀和图像的开运算来进行处理。中值滤波法是一种非线性平滑技术,它将每一像素点的像素值设置为该点某邻域窗口内的所有像素点像素值的中值。对椒盐噪声有非常好的消除作用。Sobel算子是一个离散的一阶差分算子,用来计算图像亮度函数的一阶梯度之近似值。通过使用Sobel算子能够有效的提取图像的边缘。在实验过程中还采用了拉普拉斯算子,直方图均衡化,对比度拉伸等方法,但是效果不佳。接着将sobel算子得到的图像进行二值化,最后对得到的二值化图像进行膨胀腐蚀,开运算的交替进行,消除图像中的杂点,获取有用的信息。
首先,通过将颜色处理后的图像和边缘处理后的图像二者取交集,可以得到最有可能是车牌的区域。然后通过寻找图像中所有的联结成块的区域,求出所有区域的最小外接矩形,寻找面积大于2500的,长宽比在1.5到5之间的矩形区域,对于符合条件的就用红框把矩形区域框出来。
实验结果较为不错,canon和iPhone_5s数据集中的白天的图像的车牌能够全部定位出来,hp_recorder数据集的晚上的那些车牌只能定位出4张,其中较为瑕疵的是由于有一些干扰因素,除了定位出车牌,往往也会定位出图像周围有可能是车牌的东西。例如下图
还有个别图像车牌会把车的车牌周围的黑色和铁也框进去,例如这张图后面的黑车,所选的区域稍微偏大。
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from skimage import transform,data
from numpy import *
import cv2
from scipy import misc
def kuang(res_end,img):#轮廓定位函数
hh,contours, hierarchy = cv2.findContours(res_end,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#找出所有的轮廓
for i in range(len(contours)):##对所有的轮廓进行筛选
cnt = contours[i]
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
area=cv2.contourArea(cnt)
leng=(((box[0][1]-box[1][1])**2)+((box[0][0]-box[1][0])**2))**0.5#求长
high=(((box[0][1]-box[3][1])**2)+((box[0][0]-box[3][0])**2))**0.5#求宽
if area<2500:
continue
if (leng/high<5 and leng/high>1.5) or (leng/high>0.2 and leng/high<0.66):
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img, [box], 0, (0, 0, 255), 10)
pic = cv2.resize(img, (800, 600), interpolation=cv2.INTER_CUBIC)
'''cv2.imshow('resize_pic',pic)
cv2.waitKey(0)'''
return pic#返回最后框选的结果
if __name__=="__main__":
str0 = "License_plate/canon/IMG_0" # IMG_0175.jpg
str1 = "License_plate/hp_recorder/IMG_0" # IMG_001.jpg
str2 = "License_plate/iPhone_5s/IMG_0" # IMG_0119.jpg
for tt in range(175, 200):#canon数据集操作
image = str0 + str(tt) + ".jpg"
img = cv2.imread(image)#读取图像
HSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)#转化为HSV空间
H, S, V = cv2.split(HSV)
LowerBlue = np.array([100, 100, 50])
UpperBlue = np.array([130, 255, 255])
mask = cv2.inRange(HSV, LowerBlue, UpperBlue)#进行蓝色的区分
BlueThings = cv2.bitwise_and(img, img, mask=mask)
LowerYellow = np.array([15, 150, 150])
UpperYellow = np.array([30, 255, 255])
mask = cv2.inRange(HSV, LowerYellow, UpperYellow)#进行黄色的区分
YellowThings = cv2.bitwise_and(img, img, mask=mask)
res = cv2.bitwise_or(BlueThings, YellowThings) # 黄色内容和蓝色内容取交集的结果
# 转化为灰度图
res_gray = cv2.cvtColor(res, cv2.COLOR_RGB2GRAY)
retval, res_gray = cv2.threshold(res_gray, 20, 255, cv2.THRESH_BINARY) # 二值化方法
# 进行边缘检测
tmp = str0 + str(tt) + ".jpg"
img_color = cv2.imread(tmp)
row, col, x = img_color.shape
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)#转化为灰度图
# img_gray=grey_scale(img_gray)对比度拉伸
img_gray = cv2.medianBlur(img_gray, 5) # 中值滤波,去除椒盐噪声
# gaussianResult = cv2.GaussianBlur(img_gray, (5, 5), 1.5) # 高斯模糊
# img_gray = cv2.equalizeHist(img_gray) # 直方图均衡化
x = cv2.Sobel(img_gray, cv2.CV_16S, 1, 0, ksize=3) # sobel算子
y = cv2.Sobel(img_gray, cv2.CV_16S, 0, 1, ksize=3)
#laplacian = cv2.Laplacian(img_gray, cv2.CV_16S)
absX = cv2.convertScaleAbs(x) # 转回uint8
absY = cv2.convertScaleAbs(y)
#laplacian = cv2.convertScaleAbs(laplacian)
img_gray = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
'''plt.imshow(res_end, cmap='gray')
plt.axis('off')
plt.show()'''
retval, img_gray = cv2.threshold(img_gray, 40, 255, cv2.THRESH_BINARY) # 二值化方法
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 10))
img_gray = cv2.dilate(img_gray, kernel, iterations=1)# 膨胀
img_gray = cv2.erode(img_gray, kernel)#腐蚀
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)#开运算
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)
# 边缘检测结果和颜色的结果取交集
res_end = cv2.bitwise_and(img_gray, res_gray)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (17, 17))
res_end = cv2.dilate(res_end, kernel, iterations=1)#膨胀
res_end=kuang(res_end,img)
dire = "res/canon/" + str(tt) + ".jpg"
cv2.imwrite(dire, res_end)
for tt in range(1, 30):#hp_recorder数据集操作
str1_tmp=str1
if tt>=1 and tt<=9:
str1_tmp=str1_tmp+"0"
image = str1_tmp + str(tt) + ".jpg"
img = cv2.imread(image)#读取图像
HSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)#转化为HSV空间
H, S, V = cv2.split(HSV)
LowerBlue = np.array([100, 100, 50])
UpperBlue = np.array([130, 255, 255])
mask = cv2.inRange(HSV, LowerBlue, UpperBlue)#选择出蓝色区域
BlueThings = cv2.bitwise_and(img, img, mask=mask)
LowerYellow = np.array([15, 150, 150])
UpperYellow = np.array([30, 255, 255])
mask = cv2.inRange(HSV, LowerYellow, UpperYellow)#选择出黄色区域
YellowThings = cv2.bitwise_and(img, img, mask=mask)
res = cv2.bitwise_or(BlueThings, YellowThings) # 黄色内容和蓝色内容取交集的结果
# 转化为灰度图
res_gray = cv2.cvtColor(res, cv2.COLOR_RGB2GRAY)
retval, res_gray = cv2.threshold(res_gray, 20, 255, cv2.THRESH_BINARY) # 二值化方法
# 进行边缘检测
tmp = str1_tmp + str(tt) + ".jpg"
img_color = cv2.imread(tmp)
row, col, x = img_color.shape
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)#转化为灰度图
# img_gray=grey_scale(img_gray)对比度拉伸
img_gray = cv2.medianBlur(img_gray, 5) # 中值滤波,去除椒盐噪声
# gaussianResult = cv2.GaussianBlur(img_gray, (5, 5), 1.5) # 高斯模糊
# img_gray = cv2.equalizeHist(img_gray) # 直方图均衡化
x = cv2.Sobel(img_gray, cv2.CV_16S, 1, 0, ksize=3) # sobel算子
y = cv2.Sobel(img_gray, cv2.CV_16S, 0, 1, ksize=3)
laplacian = cv2.Laplacian(img_gray, cv2.CV_16S)
absX = cv2.convertScaleAbs(x) # 转回uint8
absY = cv2.convertScaleAbs(y)
laplacian = cv2.convertScaleAbs(laplacian)
img_gray = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
retval, img_gray = cv2.threshold(img_gray, 40, 255, cv2.THRESH_BINARY) # 二值化方法
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 10)) # 膨胀
img_gray = cv2.dilate(img_gray, kernel, iterations=1)
img_gray = cv2.erode(img_gray, kernel)
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)#开运算
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)
# 边缘检测结果和颜色的结果取交集
res_end = cv2.bitwise_and(img_gray, res_gray)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (17, 17))
res_end = cv2.dilate(res_end, kernel, iterations=1)#膨胀
res_end = kuang(res_end, img)
dire = "res/hp_recorder/" + str(tt) + ".jpg"
cv2.imwrite(dire, res_end)
for tt in range(119, 155):#iPhone_5s数据集操作
image = str2 + str(tt) + ".jpg"
img = cv2.imread(image)#读取图像
HSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)#转化为HSV空间
H, S, V = cv2.split(HSV)
LowerBlue = np.array([100, 100, 50])
UpperBlue = np.array([130, 255, 255])
mask = cv2.inRange(HSV, LowerBlue, UpperBlue)#选择出蓝色区域
BlueThings = cv2.bitwise_and(img, img, mask=mask)
LowerYellow = np.array([15, 150, 150])
UpperYellow = np.array([30, 255, 255])
mask = cv2.inRange(HSV, LowerYellow, UpperYellow)#选择出黄色区域
YellowThings = cv2.bitwise_and(img, img, mask=mask)
res = cv2.bitwise_or(BlueThings, YellowThings) # 黄色内容和蓝色内容取交集的结果
# 转化为灰度图
res_gray = cv2.cvtColor(res, cv2.COLOR_RGB2GRAY)
retval, res_gray = cv2.threshold(res_gray, 20, 255, cv2.THRESH_BINARY) # 二值化方法
# 进行边缘检测
tmp = str2 + str(tt) + ".jpg"
img_color = cv2.imread(tmp)
row, col, x = img_color.shape
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
# img_gray=grey_scale(img_gray)对比度拉伸
img_gray = cv2.medianBlur(img_gray, 5) # 中值滤波,去除椒盐噪声
# gaussianResult = cv2.GaussianBlur(img_gray, (5, 5), 1.5) # 高斯模糊
# img_gray = cv2.equalizeHist(img_gray) # 直方图均衡化
x = cv2.Sobel(img_gray, cv2.CV_16S, 1, 0, ksize=3) # sobel算子
y = cv2.Sobel(img_gray, cv2.CV_16S, 0, 1, ksize=3)
laplacian = cv2.Laplacian(img_gray, cv2.CV_16S)
absX = cv2.convertScaleAbs(x) # 转回uint8
absY = cv2.convertScaleAbs(y)
laplacian = cv2.convertScaleAbs(laplacian)
img_gray = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
retval, img_gray = cv2.threshold(img_gray, 40, 255, cv2.THRESH_BINARY) # 二值化方法
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 10)) # 膨胀
img_gray = cv2.dilate(img_gray, kernel, iterations=1)
img_gray = cv2.erode(img_gray, kernel)#腐蚀
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)#开运算
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)
img_gray = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)
# 边缘检测结果和颜色的结果取交集
res_end = cv2.bitwise_and(img_gray, res_gray)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 10))
res_end = cv2.morphologyEx(res_end, cv2.MORPH_CLOSE, kernel)#开运算
res_end = cv2.dilate(res_end, kernel, iterations=1)#膨胀
res_end = cv2.morphologyEx(res_end, cv2.MORPH_CLOSE, kernel)
res_end = cv2.dilate(res_end, kernel, iterations=1)
res_end = cv2.dilate(res_end, kernel, iterations=1)
res_end = cv2.morphologyEx(res_end, cv2.MORPH_CLOSE, kernel)
res_end = kuang(res_end, img)
dire = "res/iPhone_5s/"+ str(tt) + ".jpg"
cv2.imwrite(dire, res_end)