1. 程式人生 > 實用技巧 >keras+resnet實現車牌識別

keras+resnet實現車牌識別

1.使用PIL和opencv生成車牌影象資料

from PIL import ImageFont,Image,ImageDraw
import cv2
import numpy as np
import os
from math import *
#建立 生成車牌影象資料 的類
index = {"京": 0, "滬": 1, "津": 2, "渝": 3, "冀": 4, "晉": 5, "蒙": 6, "遼": 7, "吉": 8, "黑": 9, "蘇": 10, "浙": 11, "皖": 12,
         "閩": 13, "贛": 14, "魯": 15, "豫": 16, "鄂": 17, "湘": 18, "粵": 19, "桂": 20, "瓊": 21, "川": 22, "貴": 23, "雲": 24,
         "藏": 25, "陝": 26, "甘": 27, "青": 28, "寧": 29, "新": 30, "0": 31, "1": 32, "2": 33, "3": 34, "4": 35, "5": 36,
         "6": 37, "7": 38, "8": 39, "9": 40, "A": 41, "B": 42, "C": 43, "D": 44, "E": 45, "F": 46, "G": 47, "H": 48,
         "J": 49, "K": 50, "L": 51, "M": 52, "N": 53, "P": 54, "Q": 55, "R": 56, "S": 57, "T": 58, "U": 59, "V": 60,
         "W": 61, "X": 62, "Y": 63, "Z": 64}
 
chars = ["京", "滬", "津", "渝", "冀", "晉", "蒙", "遼", "吉", "黑", "蘇", "浙", "皖", "閩", "贛", "魯", "豫", "鄂", "湘", "粵", "桂",
             "瓊", "川", "貴", "雲", "藏", "陝", "甘", "青", "寧", "新", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
             "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
             "Y", "Z"
             ]
def r(val):
    return int(np.random.random()*val)
def GenCh(f,val):#生成中文字元,f是中文字型物件,
    img=Image.new('RGB',(45,70),(255,255,255))#建立中文字元區域的全白畫布,中文一般要方正一些,所以畫布設定大一點,等下再resize
    draw=ImageDraw.Draw(img)#對畫布建立畫畫物件
    draw.text((0,3),val,(0,0,0),font=f)#畫畫物件畫出規定字型的黑色的規定val【0】文字,在左上角位置是(0,3)的點開始
    img =  img.resize((23,70))
    A=np.array(img)#圖畫轉換成array格式
    return A
def GenCh1(f,val):#生成英文和數字字元,f是中文字型物件,
    img=Image.new('RGB',(23,70),(255,255,255))
    draw=ImageDraw.Draw(img)
    draw.text((0,2),val,(0,0,0),font=f)#畫畫物件在左上角(0,2)出開始畫出val,顏色全黑,字型是f
    A=np.array(img)
    return A
def rot(img,angle,shape,max_angle):#透視畸變 
    size_o=[shape[1],shape[0]]#cv讀的(h,w)換成[w,h]
    size=(shape[1]+int(shape[0]*cos((float(max_angle)/180)*3.14)),shape[0])#【變化後的w,h】
    interval=abs(int(sin(float(angle)/180)*3.14)*shape[0])#h變換的絕對值
    pts1=np.float32([[0,0],[0,size_o[1]],[size_o[0],0],[size_o[0],size_o[1]]])#(00,0h,w0,wh)
    if (angle>0):
        pts2=np.float32([[interval,0],[0,size[1]],[size[0],0],[size[0]-interval,size_o[1]]])
    else:
        pts2 = np.float32([[0,0],[interval,size[1]  ],[size[0]-interval,0  ],[size[0],size_o[1]]])
    M=cv2.getPerspectiveTransform(pts1,pts2)#根據兩幅圖的四個座標點計算透視矩陣
    dst=cv2.warpPerspective(img,M,size)#img再M矩陣的變化下生成size大小的變化圖
    return dst
def rotRandrom(img,factor,shape):#仿射畸變
    pts1=np.float32([[0,0],[0,shape[0]],[shape[1],0],[shape[1],shape[0]]])#00,0h,w0,wh
    pts2=np.float32([[r(factor),r(factor)],[r(factor),shape[0]-r(factor)],[shape[1]-factor,r(factor)],[shape[1]-r(factor),shape[0]-r(factor)]])
    M=cv2.getPerspectiveTransform(pts1,pts2)
    dst=cv2.warpPerspective(img,M,shape)
    return dst
def tfactor(img):#新增飽和度光照的噪聲
    hsv=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
    hsv[:,:,0] = hsv[:,:,0]*(0.8+ np.random.random()*0.2)
    hsv[:,:,1] = hsv[:,:,1]*(0.3+ np.random.random()*0.7)
    hsv[:,:,2] = hsv[:,:,2]*(0.2+ np.random.random()*0.8)
    img=cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR)
    return img
def random_envirment(img,data_set):#新增自然環境噪聲
    index=r(len(data_set))
    env=cv2.imread(data_set[index])#隨機讀出一張環境噪聲圖片
    env=cv2.resize(env,(img.shape[1],img.shape[0]))#改變環境噪聲圖片的大下
    bak=(img==0)
    bak=bak.astype(np.uint8)*255#圖片的黑色部分變成白色部分
    inv=cv2.bitwise_and(bak,env)#圖片的非黑部分和噪聲求and,
    img=cv2.bitwise_or(inv,img)
    return img
def AddGauss(img,level):#新增高斯模糊
    return cv2.blur(img,(level*2+1,level*2+1))
def AddNoiseSingleChannel(single):#高斯噪聲
    diff=255-single.max()
    noise=np.random.normal(0,1+r(6),single.shape)
    noise = (noise - noise.min())/(noise.max()-noise.min())
    noise= diff*noise
    noise= noise.astype(np.uint8)
    dst = single + noise
    return dst
def addNoise(img,sdev = 0.5,avg=10):#每個通道隨機新增高斯噪聲
    img[:,:,0] =  AddNoiseSingleChannel(img[:,:,0])
    img[:,:,1] =  AddNoiseSingleChannel(img[:,:,1])
    img[:,:,2] =  AddNoiseSingleChannel(img[:,:,2])
    return img
class GenPlate:#生成車牌影象資料 的類
    def __init__(self,fontCh,fontEng,NoPlates):
        self.fontC=ImageFont.truetype(fontCh,43,0)#建立中文字型物件,fontCh是字型檔案地址,43是字型大小,規定文字字型
        self.fontE=ImageFont.truetype(fontEng,60,0)
        self.img=np.array(Image.new('RGB',(226,70),(255,255,255)))#建立(226,70)大小的全白影象,並轉換成array格式
        self.bg=cv2.resize(cv2.imread('./input_data/images/template.bmp'),(226,70))#讀取出背景模板圖
        self.smu=cv2.imread('./input_data/images/smu2.jpg')#********************************
        self.noplates_path=[]
        for parent,parent_folder,filenames in os.walk(NoPlates):#NoPlates的上級目錄,NoPlates的子目錄(沒有),NoPlates的子檔案
            for filename in filenames:
                path=parent+'/'+filename
                self.noplates_path.append(path)#環境噪聲圖片
    def draw(self,val):
        offset=2
        self.img[0:70,offset+8:offset+8+23]=GenCh(self.fontC,val[0])#再self.img畫布上畫出中文字
        self.img[0:79,offset+8+23+6:offset+8+23+6+23]=GenCh1(self.fontE,val[1])#英文字
        for i in range(5):#畫出5個數字
            base=offset+8+23+6+23+17+ i*23+ i*6
            self.img[0:70,base:base+23]=GenCh1(self.fontE,val[i+2])
        return self.img#畫出背景白色,文字黑色的文字內容
    def generate(self,text):
        if len(text)==7:
            fg=self.draw(text)#呼叫draw函式,畫出這7個字元)
            fg=cv2.bitwise_not(fg)#影象的array按位取反:黑色背景,白色文字
            com=cv2.bitwise_or(fg,self.bg)#再與背景圖片取或,則生成背景是背景圖片,前景是白色文字的圖片array格式
            com=rot(com,r(60)-30,com.shape,30)#透視畸變效果(img,angle,shape,max_angle)
            com = rotRandrom(com,10,(com.shape[1],com.shape[0]))#仿射畸變
            com = tfactor(com)#新增飽和度光照的噪聲
            com = random_envirment(com,self.noplates_path)#環境圖片的噪聲
            com = AddGauss(com, 1+r(4))#高斯模糊
            com = addNoise(com)#高斯噪聲
            return com
    def genPlateString(self,pos,val):#隨機生成(中文 英文 數字*5)的字元
        #pos!=-1時,讀取出val值就是車牌值************************pos=-1時,val隨機,主要是生成車牌
        plateStr=''
        if (pos!=-1):#
            plateStr+=val#讀出你想要生成的車牌號
        else:#隨機生成車牌號
            for cpos in range(7):
                if cpos==0:
                    plateStr+=chars[r(31)]
                elif cpos==1:
                    plateStr+=chars[41+r(24)]
                else:
                    plateStr+=chars[31+r(10)]
        return plateStr
    def genBatch(self,batchSize,size):#生成batch——size個車牌資料
        for i in range(batchSize):
            plateStr=self.genPlateString(-1,-1)
            print(plateStr)
            img=self.generate(plateStr)
            
            img=cv2.resize(img,size)
            filename=str(plateStr)+'.jpg'
            cv2.imencode('.jpg',img)[1].tofile(filename)#此處解決中文名亂碼
if __name__=='__main__':
    G=GenPlate("./input_data/font/platech.ttf",'./input_data/font/platechar.ttf',"./input_data/NoPlates")
    G.genBatch(10,(224,224))

2.使用keras生成resnet34模型