opencv-python车牌识别

opencv-python车牌识别

本文尚有很多不足的地方,例如车牌字符的定位,车牌种类的不同,复杂环境下车牌识别的问题等等。。。
不足之处请多指教

主要步骤

  1. 读入图像
  2. 颜色识别,设定阈值
  3. 掩模、按位运算
  4. 图形灰度化、二值化
  5. 边缘检测
  6. 开运算、闭运算
  7. 轮廓识别,输出矩阵
  8. 判断长宽比
  9. 找出车牌四角坐标
  10. 检测字符位置
  11. 字符切割
  12. 模板匹配,找出匹配最大值
  13. 结果输出

子函数介绍

(1)color_change(picture)函数
对输入的图片,现进行阈值的设定,不同颜色的车牌有不同的阈值,一般为蓝色,黄色和绿色。然后通过掩模运算突出二值化车牌的位置,极大的降低了其他背景对识别的干扰。然后在进行按位运算回复车牌原有的颜色,并返回处理过的图像。
颜色识别后的车牌
(2)binaryzation(value)函数
把color_change(picture)返回的结果转化为和灰度图并进行二值化,然后进行边缘检测,并对检测后的图像进行开运算和开运算,将车牌区域的轮廓连为一个整体。然后通过cv2.findContours()函数找出图像中单独的轮廓并返回。
cv2.findContours()参数说明:img为寻找轮廓的图像,且为二值图(黑白图)。
mode为轮廓的检索模式,有四种:cv2.RETR_EXTERNAL只检测外轮廓。cv2.RETR_LIST检测的轮廓不建立等级关系。cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。cv2.RETR_TREE建立一个等级树结构的轮廓。
method为轮廓的近似方法。cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1)) == 1。cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息。
返回值contours表示图像中的所有轮廓的list,np.array类型。
开闭运算输出的轮廓:
在这里插入图片描述
函数画出的轮廓:
在这里插入图片描述
(3)cut_out(value1,value2)函数
函数接收 binaryzation(value)返回的结果,利用cv2.minAreaRect(contour)函数计算识别轮廓的长宽比,确定车牌的位置。然后利用v2.boxPoints(rect)函数找出车牌四个角的坐标,最后切割车牌。
切割出的车牌:
在这里插入图片描述
(4)car_binaryzation_cut(value)函数
将cut_out(value1,value2)函数返回的图像进行二值化,然后获取图像行方向和列方向上字符的分布图,确定字符的分布位置。然后根据位置进行字符的分割。最后将分割后的字符和保存的字符库进行匹配,找出匹配度最高的图像,最后输出匹配结果。
车牌二值化的图像:
在这里插入图片描述
字符行列像素分布图:
在这里插入图片描述
字符分割后的图像:
在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述
(5)show(value,picture)函数
该函数主要用于在原始图像上添加识别后的结果,因为有汉字,所以运用PIL库进行输出。其参数为原始图像和识别后的字符串结果。
在这里插入图片描述

主代码

import cv2 
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image,ImageDraw,ImageFont

def color_change(picture):
    '''
    将图片转化到HSV空间,并按位取反,突出车牌区域
    '''
    hsv=cv2.cvtColor(picture,cv2.COLOR_BGR2HSV)     #转化为HSV颜色空间
    lower_blue=np.array([100,43,46])                              #蓝色阈值
    upper_blue=np.array([124,255,255])
    mask1=cv2.inRange(hsv,lower_blue,upper_blue)     #构建掩模
    res1=cv2.bitwise_and(image,image,mask=mask1)  #按位运算
    cv2.imwrite('111.jpg',res1)
    return res1


def binaryzation(value):
    '''
    把图象进行二值化,并进行开闭运算,最后找到可能存在的区域,并返回区域信息
    '''
    gray=cv2.cvtColor(value,cv2.COLOR_BGR2GRAY)                                          #转化为灰度图                                            
    ret,thresh=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)                       #图像二值化

    canny = cv2.Canny(thresh, 100, 200)                                                                #边缘检测
    kernel1 = np.ones((12,40), np.uint8)  
    img_edge1 = cv2.morphologyEx(canny, cv2.MORPH_CLOSE, kernel1)         # 闭运算  
    img_edge2 = cv2.morphologyEx(img_edge1, cv2.MORPH_OPEN, kernel1)  # 开运算
    cv2.imwrite('222.jpg',img_edge2)

    contours ,hierarchy = cv2.findContours(img_edge2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    #c=cv2.drawContours(image, contours, -1, (0, 255, 0), 3)
    return contours


def cut_out(value1,value2):
    '''
    通过长宽比判断车牌的位置,并截取
    '''                                
    for contour in value1:
        rect = cv2.minAreaRect(contour)   #找出最小外接矩形 中心点、宽和高、角度
        if rect[1][1]>rect[1][0]:
            k=rect[1][1]/rect[1][0]
        else:
            k=rect[1][0]/rect[1][1]
        if (k>2.5)&(k<5):    #判断车牌的轮廓
        
            a=cv2.boxPoints(rect)     #获取外接矩形的四个点
            box = np.int0(a)
            aa=cv2.drawContours(value2, [box], -1, (0, 255, 0), 3)  #找出车牌的位置     
            cv2.imwrite('aa.jpg',aa)
            x=[]
            y=[]
            for i in range(4):
                x.append(box[i][1])
                y.append(box[i][0])
            min_x=min(x)
            max_x=max(x)
            min_y=min(y)
            max_y=max(y)         
            cut=image[min_x:max_x,min_y:max_y]
            cv2.imwrite('333.jpg',cut)  
            return cut


def car_binaryzation_cut(value):
    '''
    截取车牌的二值化并切割
    '''  
    # RGB转GARY
    change_size= cv2.resize(value, (440, 140))
    gray_img = cv2.cvtColor(change_size, cv2.COLOR_BGR2GRAY)  
    ret,thresh=cv2.threshold(gray_img,127,255,cv2.THRESH_BINARY)       #图像二值化
    cv2.imwrite('444.jpg', thresh)
    
    x=list(range(440))
    y=[]
    for i in range(440):         #获取列方向上的字符像素分布图
        n=0
        for j in range(140):
            if thresh[j,i]==255:
                n=n+1
        y.append(n)
    plt.subplot(1,2,1)
    plt.plot(x,y)     
    
    x1=list(range(140))
    y1=[]
    for i in range(140):         #获取行方向上的字符像素分布图
        n=0
        for j in range(440):
            if thresh[i,j]==255:
                n=n+1
        y1.append(n)
    plt.subplot(1,2,2)
    plt.plot(x1,y1)     
    plt.show()

    p1=thresh[15:120,12:63]
    p2=thresh[15:120,65:117]
    p3=thresh[20:120,142:197]
    p4=thresh[20:120,200:260]
    p5=thresh[20:120,260:317]
    p6=thresh[20:120,320:365]
    p7=thresh[20:120,370:425]

    cv2.imshow('1',p1)
    cv2.imshow('2',p2)
    cv2.imshow('3',p3)
    cv2.imshow('4',p4)
    cv2.imshow('5',p5)
    cv2.imshow('6',p6)
    cv2.imshow('7',p7)

    p=[p1,p2,p3,p4,p5,p6,p7]
    tem=['0.jpg','5.jpg','6.jpg','7.jpg','8.jpg','9.jpg','B.jpg','C.jpg','E.jpg','J.jpg','K.jpg','M.jpg','Q.jpg','T.jpg','U.jpg','jin.jpg','chuan.jpg','yu.jpg','lu.jpg','su.jpg','ee.jpg']
    a=['0','5','6','7','8','9','B','C','E','J','K','M','Q','T','U','晋','川','豫','鲁','苏','鄂']
    ss=[]
    for i in range(7):    #模板匹配
        s=[]
        for j in range(len(tem)):
            image1=cv2.imread(tem[j],0)      #读入图像
            __,aaa=cv2.threshold(image1,127,255,cv2.THRESH_BINARY)
            bbb= cv2.resize(aaa, (50, 100))
            result=cv2.matchTemplate(p[i],bbb,cv2.TM_CCOEFF_NORMED)
            min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
            s.append(max_val)
        ss.append(a[s.index(max(s))])
    car=ss[0]+ss[1]+'.'+ss[2]+ss[3]+ss[4]+ss[5]+ss[6]
    print(car)
    return car


def show(value,picture):
      cv2img = cv2.cvtColor(picture, cv2.COLOR_BGR2RGB) # cv2和PIL中颜色的hex码的储存顺序不同
      pilimg = Image.fromarray(cv2img)
      # PIL图片上打印汉字
      draw = ImageDraw.Draw(pilimg) # 图片上打印
      font = ImageFont.truetype("simhei.ttf", 40, encoding="utf-8") # 参数1:字体文件路径,参数2:字体大小
      draw.text((200, 200), value, (255, 0, 0), font=font) # 参数1:打印坐标,参数2:文本,参数3:字体颜色,参数4:字体
 
      # PIL图片转cv2 图片
      cv2charimg = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)
      cv2.imshow("result", cv2charimg)
      cv2.imwrite('555.jpg',cv2charimg)


if __name__=='__main__':                                    
    image=cv2.imread('bbb.jpg')     #读入图像
    image = cv2.resize(image, (570, 430))
    
    res=color_change(image)        #转化到HSV,并大致取出车牌位置
    a=binaryzation(res)                  #对颜色识别过的区域进行二值化,并进行开闭运算识别轮廓
    b=cut_out(a,image)                  #找到符合条件的区域,并进行切割
    c=car_binaryzation_cut(b)
    show(c,image)

    while(1):
        k=cv2.waitKey(5)&0xFF
        if k==27:
            cv2.destroyAllWindows()
            break

  • 17
    点赞
  • 169
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值