python-opencv实战:车牌识别(⼀):精度还不错的车牌定位
本⽂为基于python的opencv的车牌定位源码+讲解。
⽂章⽬录
⼀. 车牌定位整体构架
1. 整体思路
⾸先,车牌定位是车牌识别的第⼀步也是必要的⼀步,同时,车牌定位的好坏直接性的决定了车牌识别的好坏,因此车牌定位是⼀定要尽量好的实现。对⼀张图⽚来说,车牌定位的⼏个过程其实很简单。
1. 去除噪⾳
2. 通过颜⾊特征筛选(或者通过形状筛选)
3. 通过形态特征再筛选(或通过颜⾊特征再筛选)
4. 定位候选区域列表
5. 选出最优的候选区域
6. 画出矩形,返回矩形的对⾓顶点。
其实过程并不复杂,但是每⼀步的各种操作混杂在⼀块就令如我这样的⼩⽩懵。不过问题不⼤,我们分开来看。
2. 分析原理
选择从通过形态特征先筛选⼊⼿。
先将图⽚转化为灰度图(边缘检测和轮廓识别需要灰度图),要去除噪⾳,防⽌不必要的⼲扰,通过灰度拉伸算法获取效果更良好的灰度图。做边缘检测,轮廓发现,之后出所有的矩形轮廓,利⽤国内车牌的特征选出最优的⼏个轮廓。接着对这⼏个轮廓进⾏⾊彩特征分析,转化为HSV⾊彩空间(为了使⽤inrange⽅法出掩膜),出掩膜,利⽤算法求得每个掩膜的评分,选出最优评分的掩膜,并返回其图⽚下标。是不是⼀⽓呵成。
3. 算法构造
要实现良好的车牌定位,肯定是不能直接⽤其固定好的API因为,API终究是局限于语⾔,它考虑的没有办法像活⽣⽣的⼈那么多。如果你⾜够优秀的话,⼀定程度上是可以超越API的。
①. 灰度拉伸算法
灰度拉伸⼜叫对⽐度拉伸,它是最基本的⼀种灰度变换,使⽤的是最简单的分段线性变换函数,它的主要思想是提⾼图像处理时灰度级的动态范围。它可以改善图像,说的⽩⼀点,它可以让有些不可见的地⽅变得可见。这是防⽌图⽚的拍摄⾓度或者光线问题导致车牌不清晰。
公式:g(x,y) = 255 / (B - A) * [f(x,y) - A]
②. ⼆值化的阈值选取
图像⼆值化时边缘检测的必备,我们学习过⼆值化,不论是⾃适应⼆值化,还是otus⼆值化,其⾃动算出的阈值在部分图的表现很好,但我们不能直接带⼊车牌图像,因为APi提供的⼆值化时考虑全图,或者⼀个个部分块,但是我们需要的是⾜够清晰不会影响到车牌轮廓的⼆值化。因此选择⾃⼰构造阈值。
个⼈建议利⽤阈值如下:
ret=max_value-(max_value-min_value)/2
其中为最⼤像素点和最⼩像素点,不妨思考⼀下,如果图⽚为⼀张纯⾊图,那么阈值就为该像素值。如果图⽚是最⼤为250最⼩为0那么阈值为122,蓝⾊和⽩⾊为⾼像素值,这样⽆论如何都能出其合适的轮廓。
③. 合适的分值的选取
学习⽬标识别的朋友⼀定经常和分值打交道把,通过⼀系列⽅法选出待选区域,最后评分,没有达到期望,就继续循环,继续评分,直到满⾜或者循环停⽌。
这⾥的评分当然没有⽤到神经⽹络的东西,⽽是利⽤选好的掩膜的像素值来评掩膜得到的像素值是255与0,那么我们寻掩膜的条件是蓝⾊,注意这个蓝⾊,那么是不是可以想象,如果蓝⾊够多,那么分就够⾼呢,当然可以,于是可以对每个图像得到的HSV三个通道进⾏加权求和,若是分数最够则认定为车牌,⽬前测试的图⽚,该⽅法吗,没有失败的。
⼆. 代码
'''
车牌识别
2021/2/24 python3.6 by ksks14
'''
#导库
import cv2 as cv
import numpy as np
import os
#⽅法
#导⼊图⽚资源 path为路径
def load_image(path):
src=cv.imread(path)
return src
#灰度拉伸⽅法
'''
它可以有选择的拉伸某段灰度区间以改善输出图像,如果⼀幅图像的灰度集中
在较暗的区域⽽导致图像偏暗,可以⽤灰度拉伸功能来拉伸(斜率>1)物体灰度区间以改善图像;同样如果图像灰度集中在较亮的区域⽽导致图像偏亮,也可以⽤灰
度拉伸功能来压缩(斜率<1)物体灰度区间以改善图像质量。
灰度拉伸
定义:灰度拉伸,也称对⽐度拉伸,是⼀种简单的线性点运算。作⽤:扩展图像的
直⽅图,使其充满整个灰度等级范围内
公式:
g(x,y) = 255 / (B - A) * [f(x,y) - A],
其中,A = min[f(x,y)],最⼩灰度级;B = max[f(x,y)],最⼤灰度级;
f(x,y)为输⼊图像,g(x,y)为输出图像
缺点:如果灰度图像中最⼩值A=0,最⼤值B=255,则图像没有什么改变
'''
def gray_stretch(image):
max_value=float(image.max())
min_value=float(image.min())
for i in range(image.shape[0]):
for j in range(image.shape[1]):
image[i,j]=(255/(max_value-min_value)*image[i,j]-(255*min_value)/(max_value-min_value))
return image
'''
图像整体⼆值化
'''
def image_binary(image):
def image_binary(image):
max_value=float(image.max())
min_value=float(image.min())
'''
这⾥利⽤⾃适应⼆值化以及⾃动求阈值的⽅法明显效果不好。因此设置阈值这样设置的效果很容易想到,当图⽚为⼀张纯⾊图时阈值为对应像素值,当图包含
255与0时,阈值为122,总体的适应的效果会⽐较好。⽅法返回⼆值图
'''
ret=max_value-(max_value-min_value)/2
ret,thresh=cv.threshold(image,ret,255,cv.THRESH_BINARY)
return thresh
'''
矩形轮廓⾓点,寻到矩形之后记录⾓点,⽤来做参考以及画图。
'''
def find_rectangle(contour):
y,x=[],[]
for value in contour:
y.append(value[0][0])
x.append(value[0][1])
return[min(y),min(x),max(y),max(x)]
'''
车牌定位⽅法,需要两个参数,第⼀个是⽤来寻位置,第⼆个为原图,⽤来绘制矩形。寻位置的图⽚为经过⼏次形态学操作的图⽚。这⾥利⽤权值的操作,实
现了定位的最⾼概率。
'''
def loacte_plate(image,after):
'''
定位车牌号
'''
#寻轮廓
contours,hierarchy=cv.findContours(image,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
img_copy = py()
#出最⼤的三个区域
solving=[]
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])
solving.append([r,a,s])
#通过参考选出⾯积最⼤的区域
solving=sorted(solving,key=lambda b: b[1])[-3:]
#颜⾊识别
rectangle函数opencv
maxweight,maxindex=0,-1
for i in range(len(solving)):#
wait_solve=after[solving[i][0][1]:solving[i][0][3],solving[i][0][0]:solving[i][0][2]]
#BGR转HSV
hsv=cv.cvtColor(wait_solve,cv.COLOR_BGR2HSV)
#蓝⾊车牌的范围 Hsv⾊彩空间的设置。
lower=np.array([100,50,50])
upper=np.array([140,255,255])
#利⽤inrange出掩膜
mask=cv.inRange(hsv,lower,upper)
#计算权值⽤来判断。
w1=0
for m in mask:
w1+=m/255
w2=0
for n in w1:
w2+=n
#选出最⼤权值的区域
if w2>maxweight:
maxindex=i
maxindex=i
maxweight=w2
return solving[maxindex][0]
'''
框出车牌获取位置坐标,并返回图像
'''
#对图像的预处理
def find_plates(image):
size(image,(400,int(400* image.shape[0]/ image.shape[1])))
#转换为灰度图像
gray_image=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
#灰度拉伸
#如果⼀幅图像的灰度集中在较暗的区域⽽导致图像偏暗,可以⽤灰度拉伸功能来拉伸(斜率>1)物体灰度区间以改善图像;# 同样如果图像灰度集中在较亮的区域⽽导致图像偏亮,也可以⽤灰度拉伸功能来压缩(斜率<1)物体灰度区间以改善图像质量    stretchedimage=gray_stretch(gray_image)#进⾏灰度拉伸,是因为可以改善图像的质量
'''进⾏开运算,⽤来去除噪声'''
#构造卷积核
StructuringElement(cv.MORPH_ELLIPSE,(30,30))
#开运算
phologyEx(stretchedimage,cv.MORPH_OPEN,kernel)
#获取差分图,两幅图像做差  cv2.absdiff('图像1','图像2')
strtimage=cv.absdiff(stretchedimage,openingimage)
#图像⼆值化
binaryimage=image_binary(strtimage)
#canny边缘检测
canny=cv.Canny(binaryimage,binaryimage.shape[0],binaryimage.shape[1])
#5 24效果最好
s((5,24),np.uint8)
phologyEx(canny,cv.MORPH_CLOSE,kernel)
phologyEx(closingimage,cv.MORPH_OPEN,kernel)
#11 6的效果最好
s((11,6),np.uint8)
phologyEx(openingimage,cv.MORPH_OPEN,kernel)
#消除⼩区域,定位车牌位置
rect=loacte_plate(openingimage,image)#rect包括轮廓的左上点和右下点,长宽⽐以及⾯积
#展⽰图像
cv.imshow('image',image)
cv.imshow('after', image)
cv.waitKey(0)
cv.destroyAllWindows()
def runing():
file_path='.\\plates'
for filewalks in os.walk(file_path):
for files in filewalks[2]:
print('正在处理',os.path.join(filewalks[0],files))
find_plates(load_image(os.path.join(filewalks[0],files)))
runing()
结果如下:
总结
搞定度车牌定位不仅仅是算法需要⼀些⾃⼰设置⼀些改进,同时对卷积核的设定也⼗分重要,建议⼤家可以试⼀下,⽤循环遍历的⽅法去最优,也可以从数学⾓度分析。这⾥就不多阐述了。之后会写关于字符分割的博客,这俩步基础完了就该到深度学习了。距离⽐赛还有⼀个⽉。。我时间也不多了。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。