车牌识别(一)——车牌定位(附详细代码及注释)

车牌识别分三步:车牌定位,车牌字符分割,车牌字符识别。
本篇就车牌定位进行讲述。车牌定位顾名思义——找出车牌的位置。如何实现,又分三步:图像预处理,数学形态学粗定位,长宽比例精确定位。

首先,对图像预处理:

  1. 彩色图像转灰度图
  2. 高斯滤波,中值滤波
  3. 边缘化检测
  4. 二值化操作
#-*- coding: utf-8 -*-
import cv2
import numpy as np
 
def Process(img):

	# 高斯平滑
	gaussian = cv2.GaussianBlur(img, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
	#cv2.GaussianBlur(src,ksize,sigmaX[,sigmaxY[,borderType]]])高斯滤波函数
	#src: 输入图像
	#ksize: 高斯内核大小,元组类型
	#sigmaX: 高斯核函数在X方向上的标准偏差
	#sigmaY: 高斯核函数在Y方向上的标准偏差,如果sigmaY是0,则函数会自动将sigmaY的值设置为与sigmaX相同的值,如果sigmaX和sigmaY都是0,这两个值将由ksize[0]和ksize[1]计算而来。建议将size、sigmaX和sigmaY都指定出来。
	#borderType: 推断图像外部像素的某种便捷模式,有默认值cv2.BORDER_DEFAULT,如果没有特殊需要不用更改,具体可以参考borderInterpolate()函数。
	
	# 中值滤波
	median = cv2.medianBlur(gaussian, 5)
	#cv2.medianBlur(src,ksize)
	#src: 输入图像
	#ksize: 高斯内核大小,元组类型

	# Sobel算子
	# 梯度方向: x
	sobel = cv2.Sobel(median, cv2.CV_8U, 1, 0, ksize=3)
	# 利用Sobel方法可以进行sobel边缘检测
  	# img表示源图像,即进行边缘检测的图像
	# 图像深度是cv2.CV_8U、cv2.CV_16U、cv2.CV_16S、cv2.CV_32F以及cv2.CV_64F其中的某一个
	# 第三和第四个参数分别是对X和Y方向的导数(即dx,dy),对于图像来说就是差分,这里1表示对X求偏导(差分),0表示不对Y求导(差分)。其中,X还可以求2次导。
	# 注意:对X求导就是检测X方向上是否有边缘。
	# 第五个参数ksize是指核的大小。
	# 这里说明一下,这个参数的前四个参数都没有给谁赋值,而ksize则是被赋值的对象
	# 实际上,这是可省略的参数,而前四个是不可省的参数。注意其中的不同点值化
	
	ret, binary = cv2.threshold(sobel, 170, 255, cv2.THRESH_BINARY)
	#灰度值小于175的点置0,灰度值大于175的点置255
	#最后的参数是阈值类型,对应一个公式,一般用这个就可以

然后,数学形态学处理: 形态学处理的核心就是定义结构元素,一般情况下对二值化图像进行的操作。

	# 膨胀和腐蚀操作的核函数
	element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
	element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 7))
	#第一个参数定义结构元素,如椭圆(MORPH_ELLIPSE)、交叉形结构(MORPH_CROSS)和矩形(MORPH_RECT)
	#第二个参数就是指和函数的size,9×1
  
	# 膨胀一次,让轮廓突出
	dilation = cv2.dilate(binary, element2, iterations=1)
	# 腐蚀一次,去掉细小杂点
	erosion = cv2.erode(dilation, element1, iterations=1)
	# 再次膨胀,让轮廓更明显
	dilation2 = cv2.dilate(erosion, element2, iterations=3)
	
	#存储中间图片 
    cv2.imwrite("binary.png", binary)
    cv2.imwrite("dilation.png", dilation)
    cv2.imwrite("erosion.png", erosion)
    cv2.imwrite("dilation2.png", dilation2)
    
	return dilation2

最后:查找轮廓,精确定位

  1. 查找筛选轮廓
  2. 车牌长宽比
  3. 颜色判断(没大必要)
def GetRegion(img):
	regions = []
	# 查找轮廓
	_, contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
	#三个输入参数:输入图像(二值图像),轮廓检索方式,轮廓近似方法
	#轮廓检索方式:cv2.RETR_EXTERNAL	只检测外轮廓。cv2.RETR_LIST	检测的轮廓不建立等级关系。cv2.RETR_CCOMP	建立两个等级的轮廓,上面一层为外边界,里面一层为内孔的边界信息。cv2.RETR_TREE	建立一个等级树结构的轮廓
	#轮廓近似方法:cv2.CHAIN_APPROX_NONE	存储所有边界点。cv2.CHAIN_APPROX_SIMPLE	压缩垂直、水平、对角方向,只保留端点。cv2.CHAIN_APPROX_TX89_L1	使用teh-Chini近似算法。cv2.CHAIN_APPROX_TC89_KCOS	使用teh-Chini近似算法
	#三个返回值:图像,轮廓,轮廓的层析结构

    #筛选面积小的
	for contour in contours:
	    #计算该轮廓的面积
		area = cv2.contourArea(contour)
		#面积小的都筛选掉
		if (area < 2000):
			continue
		#轮廓近似,作用很小
		epslion = 1e-3 * cv2.arcLength(contour, True)
		approx = cv2.approxPolyDP(contour, epslion, True)
		#epsilon,是从轮廓到近似轮廓的最大距离。是一个准确率参数,好的epsilon的选择可以得到正确的输出。True决定曲线是否闭合。
		# 找到最小的矩形,该矩形可能有方向
		rect = cv2.minAreaRect(contour)
		# box是四个点的坐标
		box = cv2.boxPoints(rect)
		box = np.int0(box)
		## 计算高和宽
		height = abs(box[0][1] - box[2][1])
		width = abs(box[0][0] - box[2][0])
		#车牌正常情况下长高比在2-5之间
		ratio =float(width) / float(height)
		if (ratio < 5 and ratio > 2):
			regions.append(box)
	return regions
	
def detect(img):
	# 灰度化
	gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
	# 预处理及形态学处理,得到可以查找矩形的图片
	prc = Process(gray)
	#得到车牌轮廓
	regions = GetRegion(prc)
	print('[INFO]:Detect %d license plates' % len(regions))
	#用绿线画出这些找到的轮廓
	for box in regions:
		cv2.drawContours(img, [box], 0, (0, 255, 0), 2)
        #五个输入参数:原始图像,轮廓,轮廓的索引(当设置为-1时,绘制所有轮廓),画笔颜色,画笔大小
        #一个返回值:返回绘制了轮廓的图像
	cv2.imshow('Result', img)
    #保存结果文件名
	cv2.imwrite('result.jpg', img)
	cv2.waitKey(0)
	cv2.destroyAllWindows()
 
if __name__ == '__main__':
    #输入的参数为图片的路径
	img = cv2.imread('1.jpg')
	detect(img)
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值