zoukankan      html  css  js  c++  java
  • 【深度学习系列】车牌识别实践(一)

      小伙伴们,终于到了实战部分了!今天给大家带来的项目是用PaddlePaddle进行车牌识别。车牌识别其实属于比较常见的图像识别的项目了,目前也属于比较成熟的应用,大多数老牌厂家能做到准确率99%+。传统的方法需要对图像进行多次预处理再用机器学习的分类算法进行分类识别,然而深度学习发展起来以后,我们可以通过用CNN来进行端对端的车牌识别。任何模型的训练都离不开数据,在车牌识别中,除了晚上能下载到的一些包含车牌的数据是不够的,本篇文章的主要目的是教大家如何批量生成车牌。


    生成车牌数据

      1.定义车牌数据所需字符

      车牌中包括省份简称、大写英文字母和数字,我们首先定义需要的字符和字典,方便后面使用

     1 index = {"": 0, "": 1, "": 2, "": 3, "": 4, "": 5, "": 6, "": 7, "": 8, "": 9, "": 10, "": 11, "": 12,
     2          "": 13, "": 14, "": 15, "": 16, "": 17, "": 18, "": 19, "": 20, "": 21, "": 22, "": 23, "": 24,
     3          "": 25, "": 26, "": 27, "": 28, "": 29, "": 30, "0": 31, "1": 32, "2": 33, "3": 34, "4": 35, "5": 36,
     4          "6": 37, "7": 38, "8": 39, "9": 40, "A": 41, "B": 42, "C": 43, "D": 44, "E": 45, "F": 46, "G": 47, "H": 48,
     5          "J": 49, "K": 50, "L": 51, "M": 52, "N": 53, "P": 54, "Q": 55, "R": 56, "S": 57, "T": 58, "U": 59, "V": 60,
     6          "W": 61, "X": 62, "Y": 63, "Z": 64};
     7 
     8 chars = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
     9              "", "", "", "", "", "", "", "", "", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
    10              "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
    11              "Y", "Z"
    12              ];

      

      2.生成中英文字符

     1 def GenCh(f,val):
     2     """
     3     生成中文字符
     4     """
     5     img=Image.new("RGB", (45,70),(255,255,255))
     6     draw = ImageDraw.Draw(img)
     7     draw.text((0, 3),val,(0,0,0),font=f)
     8     img =  img.resize((23,70))
     9     A = np.array(img)
    10     return A
    11 
    12 def GenCh1(f,val):
    13     """
    14     生成英文字符
    15     """
    16     img=Image.new("RGB", (23,70),(255,255,255))
    17     draw = ImageDraw.Draw(img)
    18     draw.text((0, 2),val.decode('utf-8'),(0,0,0),font=f)
    19     A = np.array(img)
    20     return A

      

      3.对数据添加各种噪音和畸变,模糊处理

     1 def AddSmudginess(img, Smu):
     2     rows = r(Smu.shape[0] - 50)
     3     cols = r(Smu.shape[1] - 50)
     4     adder = Smu[rows:rows + 50, cols:cols + 50];
     5     adder = cv2.resize(adder, (50, 50));
     6     #adder = cv2.bitwise_not(adder)
     7     img = cv2.resize(img,(50,50))
     8     img = cv2.bitwise_not(img)
     9     img = cv2.bitwise_and(adder, img)
    10     img = cv2.bitwise_not(img)
    11     return img
    12 
    13 
    14 def rot(img,angel,shape,max_angel):
    15     """
    16         添加放射畸变
    17         img 输入图像
    18         factor 畸变的参数
    19         size 为图片的目标尺寸
    20     """
    21     size_o = [shape[1],shape[0]]
    22     size = (shape[1]+ int(shape[0]*cos((float(max_angel )/180) * 3.14)),shape[0])
    23     interval = abs( int( sin((float(angel) /180) * 3.14)* shape[0]));
    24     pts1 = np.float32([[0,0],[0,size_o[1]],[size_o[0],0],[size_o[0],size_o[1]]])
    25     if(angel>0):
    26         pts2 = np.float32([[interval,0],[0,size[1]  ],[size[0],0  ],[size[0]-interval,size_o[1]]])
    27     else:
    28         pts2 = np.float32([[0,0],[interval,size[1]  ],[size[0]-interval,0  ],[size[0],size_o[1]]])
    29     M  = cv2.getPerspectiveTransform(pts1,pts2);
    30     dst = cv2.warpPerspective(img,M,size);
    31     return dst
    32 
    33 
    34 def rotRandrom(img, factor, size):
    35     """
    36     添加透视畸变
    37     """
    38     shape = size;
    39     pts1 = np.float32([[0, 0], [0, shape[0]], [shape[1], 0], [shape[1], shape[0]]])
    40     pts2 = np.float32([[r(factor), r(factor)], [ r(factor), shape[0] - r(factor)], [shape[1] - r(factor),  r(factor)],
    41                        [shape[1] - r(factor), shape[0] - r(factor)]])
    42     M = cv2.getPerspectiveTransform(pts1, pts2);
    43     dst = cv2.warpPerspective(img, M, size);
    44     return dst
    45 
    46 def tfactor(img):
    47     """
    48     添加饱和度光照的噪声
    49     """
    50     hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV);
    51     hsv[:,:,0] = hsv[:,:,0]*(0.8+ np.random.random()*0.2);
    52     hsv[:,:,1] = hsv[:,:,1]*(0.3+ np.random.random()*0.7);
    53     hsv[:,:,2] = hsv[:,:,2]*(0.2+ np.random.random()*0.8);
    54 
    55     img = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR);
    56     return img
    57 
    58 def random_envirment(img,data_set):
    59     """
    60     添加自然环境的噪声
    61     """
    62     index=r(len(data_set))
    63     env = cv2.imread(data_set[index])
    64     env = cv2.resize(env,(img.shape[1],img.shape[0]))
    65     bak = (img==0);
    66     bak = bak.astype(np.uint8)*255;
    67     inv = cv2.bitwise_and(bak,env)
    68     img = cv2.bitwise_or(inv,img)
    69     return img
    70 
    71 def AddGauss(img, level):
    72     """
    73     添加高斯模糊
    74     """
    75     return cv2.blur(img, (level * 2 + 1, level * 2 + 1));
    76 
    77 def r(val):
    78     return int(np.random.random() * val)
    79 
    80 def AddNoiseSingleChannel(single):
    81     """
    82     添加高斯噪声
    83     """
    84     diff = 255-single.max();
    85     noise = np.random.normal(0,1+r(6),single.shape);
    86     noise = (noise - noise.min())/(noise.max()-noise.min())
    87     noise= diff*noise;
    88     noise= noise.astype(np.uint8)
    89     dst = single + noise
    90     return dst
    91 
    92 def addNoise(img,sdev = 0.5,avg=10):
    93     img[:,:,0] =  AddNoiseSingleChannel(img[:,:,0]);
    94     img[:,:,1] =  AddNoiseSingleChannel(img[:,:,1]);
    95     img[:,:,2] =  AddNoiseSingleChannel(img[:,:,2]);
    96     return img

      

      4.加入背景图片,生成车牌字符串list和label,并存为图片格式,批量生成。

     1 class GenPlate:
     2 
     3     def __init__(self,fontCh,fontEng,NoPlates):
     4         self.fontC =  ImageFont.truetype(fontCh,43,0);
     5         self.fontE =  ImageFont.truetype(fontEng,60,0);
     6         self.img=np.array(Image.new("RGB", (226,70),(255,255,255)))
     7         self.bg  = cv2.resize(cv2.imread("./images/template.bmp"),(226,70));
     8         self.smu = cv2.imread("./images/smu2.jpg");
     9         self.noplates_path = [];
    10         for parent,parent_folder,filenames in os.walk(NoPlates):
    11             for filename in filenames:
    12                 path = parent+"/"+filename;
    13                 self.noplates_path.append(path);
    14 
    15 
    16     def draw(self,val):
    17         offset= 2 ;
    18         self.img[0:70,offset+8:offset+8+23]= GenCh(self.fontC,val[0]);
    19         self.img[0:70,offset+8+23+6:offset+8+23+6+23]= GenCh1(self.fontE,val[1]);
    20         for i in range(5):
    21             base = offset+8+23+6+23+17 +i*23 + i*6 ;
    22             self.img[0:70, base  : base+23]= GenCh1(self.fontE,val[i+2]);
    23         return self.img
    24     
    25     def generate(self,text):
    26         if len(text) == 9:
    27             fg = self.draw(text.decode(encoding="utf-8"));
    28             fg = cv2.bitwise_not(fg);
    29             com = cv2.bitwise_or(fg,self.bg);
    30             com = rot(com,r(60)-30,com.shape,30);
    31             com = rotRandrom(com,10,(com.shape[1],com.shape[0]));
    32             com = tfactor(com)
    33             com = random_envirment(com,self.noplates_path);
    34             com = AddGauss(com, 1+r(4));
    35             com = addNoise(com);
    36             return com
    37 
    38     def genPlateString(self,pos,val):
    39         '''
    40     生成车牌String,存为图片
    41         生成车牌list,存为label
    42         '''
    43         plateStr = "";
    44         plateList=[]
    45         box = [0,0,0,0,0,0,0];
    46         if(pos!=-1):
    47             box[pos]=1;
    48         for unit,cpos in zip(box,range(len(box))):
    49             if unit == 1:
    50                 plateStr += val
    51                 #print plateStr
    52                 plateList.append(val)
    53             else:
    54                 if cpos == 0:
    55                     plateStr += chars[r(31)]
    56                     plateList.append(plateStr)
    57                 elif cpos == 1:
    58                     plateStr += chars[41+r(24)]
    59                     plateList.append(plateStr)
    60                 else:
    61                     plateStr += chars[31 + r(34)]
    62                     plateList.append(plateStr)
    63         plate = [plateList[0]]
    64         b = [plateList[i][-1] for i in range(len(plateList))]
    65         plate.extend(b[1:7])
    66         return plateStr,plate
    67 
    68     # 将生成的车牌图片写入文件夹,对应的label写入label.txt
    69     def genBatch(self, batchSize,pos,charRange, outputPath,size):
    70         if (not os.path.exists(outputPath)):
    71             os.mkdir(outputPath)
    72     outfile = open('label.txt','w')
    73         for i in xrange(batchSize):
    74                 plateStr,plate = G.genPlateString(-1,-1)
    75                 print plateStr,plate
    76         img =  G.generate(plateStr);
    77                 img = cv2.resize(img,size);
    78                 cv2.imwrite(outputPath + "/" + str(i).zfill(2) + ".jpg", img);
    79         outfile.write(str(plate)+"
    ")
    80 G = GenPlate("./font/platech.ttf",'./font/platechar.ttf',"./NoPlates")

      完整代码:

      1 #coding=utf-8
      2 """ 
      3    genPlate.py:生成随机车牌
      4 """
      5 
      6 __author__ = "Huxiaoman"
      7 __copyright__ = "Copyright (c) 2017 "
      8 
      9 import PIL
     10 from PIL import ImageFont
     11 from PIL import Image
     12 from PIL import ImageDraw
     13 import cv2;
     14 import numpy as np;
     15 import os;
     16 from math import *
     17 import sys
     18 
     19 
     20 index = {"": 0, "": 1, "": 2, "": 3, "": 4, "": 5, "": 6, "": 7, "": 8, "": 9, "": 10, "": 11, "": 12,
     21          "": 13, "": 14, "": 15, "": 16, "": 17, "": 18, "": 19, "": 20, "": 21, "": 22, "": 23, "": 24,
     22          "": 25, "": 26, "": 27, "": 28, "": 29, "": 30, "0": 31, "1": 32, "2": 33, "3": 34, "4": 35, "5": 36,
     23          "6": 37, "7": 38, "8": 39, "9": 40, "A": 41, "B": 42, "C": 43, "D": 44, "E": 45, "F": 46, "G": 47, "H": 48,
     24          "J": 49, "K": 50, "L": 51, "M": 52, "N": 53, "P": 54, "Q": 55, "R": 56, "S": 57, "T": 58, "U": 59, "V": 60,
     25          "W": 61, "X": 62, "Y": 63, "Z": 64};
     26 
     27 chars = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
     28              "", "", "", "", "", "", "", "", "", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
     29              "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
     30              "Y", "Z"
     31              ];
     32 
     33 def AddSmudginess(img, Smu):
     34     rows = r(Smu.shape[0] - 50)
     35     cols = r(Smu.shape[1] - 50)
     36     adder = Smu[rows:rows + 50, cols:cols + 50];
     37     adder = cv2.resize(adder, (50, 50));
     38     #adder = cv2.bitwise_not(adder)
     39     img = cv2.resize(img,(50,50))
     40     img = cv2.bitwise_not(img)
     41     img = cv2.bitwise_and(adder, img)
     42     img = cv2.bitwise_not(img)
     43     return img
     44 
     45 def rot(img,angel,shape,max_angel):
     46     """ 
     47         添加放射畸变
     48         img 输入图像
     49         factor 畸变的参数
     50         size 为图片的目标尺寸
     51     """
     52     size_o = [shape[1],shape[0]]
     53     size = (shape[1]+ int(shape[0]*cos((float(max_angel )/180) * 3.14)),shape[0])
     54     interval = abs( int( sin((float(angel) /180) * 3.14)* shape[0]));
     55     pts1 = np.float32([[0,0],[0,size_o[1]],[size_o[0],0],[size_o[0],size_o[1]]])
     56     if(angel>0):
     57         pts2 = np.float32([[interval,0],[0,size[1]  ],[size[0],0  ],[size[0]-interval,size_o[1]]])
     58     else:
     59         pts2 = np.float32([[0,0],[interval,size[1]  ],[size[0]-interval,0  ],[size[0],size_o[1]]])
     60     M  = cv2.getPerspectiveTransform(pts1,pts2);
     61     dst = cv2.warpPerspective(img,M,size);
     62     return dst
     63 
     64 def rotRandrom(img, factor, size):
     65     """
     66     添加透视畸变
     67     """
     68     shape = size;
     69     pts1 = np.float32([[0, 0], [0, shape[0]], [shape[1], 0], [shape[1], shape[0]]])
     70     pts2 = np.float32([[r(factor), r(factor)], [ r(factor), shape[0] - r(factor)], [shape[1] - r(factor),  r(factor)],
     71                        [shape[1] - r(factor), shape[0] - r(factor)]])
     72     M = cv2.getPerspectiveTransform(pts1, pts2);
     73     dst = cv2.warpPerspective(img, M, size);
     74     return dst
     75 
     76 def tfactor(img):
     77     """
     78     添加饱和度光照的噪声
     79     """
     80     hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV);
     81     hsv[:,:,0] = hsv[:,:,0]*(0.8+ np.random.random()*0.2);
     82     hsv[:,:,1] = hsv[:,:,1]*(0.3+ np.random.random()*0.7);
     83     hsv[:,:,2] = hsv[:,:,2]*(0.2+ np.random.random()*0.8);
     84 
     85     img = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR);
     86     return img
     87 
     88 def random_envirment(img,data_set):
     89     """
     90     添加自然环境的噪声    
     91     """
     92     index=r(len(data_set))
     93     env = cv2.imread(data_set[index])
     94     env = cv2.resize(env,(img.shape[1],img.shape[0]))
     95     bak = (img==0);
     96     bak = bak.astype(np.uint8)*255;
     97     inv = cv2.bitwise_and(bak,env)
     98     img = cv2.bitwise_or(inv,img)
     99     return img
    100 
    101 def GenCh(f,val):
    102     """
    103     生成中文字符
    104     """
    105     img=Image.new("RGB", (45,70),(255,255,255))
    106     draw = ImageDraw.Draw(img)
    107     draw.text((0, 3),val,(0,0,0),font=f)
    108     img =  img.resize((23,70))
    109     A = np.array(img)
    110     return A
    111 
    112 def GenCh1(f,val):
    113     """
    114     生成英文字符
    115     """
    116     img=Image.new("RGB", (23,70),(255,255,255))
    117     draw = ImageDraw.Draw(img)
    118     draw.text((0, 2),val.decode('utf-8'),(0,0,0),font=f)
    119     A = np.array(img)
    120     return A
    121 
    122 def AddGauss(img, level):
    123     """
    124     添加高斯模糊
    125     """ 
    126     return cv2.blur(img, (level * 2 + 1, level * 2 + 1));
    127 
    128 def r(val):
    129     return int(np.random.random() * val)
    130 
    131 def AddNoiseSingleChannel(single):
    132     """
    133     添加高斯噪声
    134     """
    135     diff = 255-single.max();
    136     noise = np.random.normal(0,1+r(6),single.shape);
    137     noise = (noise - noise.min())/(noise.max()-noise.min())
    138     noise= diff*noise;
    139     noise= noise.astype(np.uint8)
    140     dst = single + noise
    141     return dst
    142 
    143 def addNoise(img,sdev = 0.5,avg=10):
    144     img[:,:,0] =  AddNoiseSingleChannel(img[:,:,0]);
    145     img[:,:,1] =  AddNoiseSingleChannel(img[:,:,1]);
    146     img[:,:,2] =  AddNoiseSingleChannel(img[:,:,2]);
    147     return img
    148 
    149 
    150 class GenPlate:
    151 
    152     def __init__(self,fontCh,fontEng,NoPlates):
    153         self.fontC =  ImageFont.truetype(fontCh,43,0);
    154         self.fontE =  ImageFont.truetype(fontEng,60,0);
    155         self.img=np.array(Image.new("RGB", (226,70),(255,255,255)))
    156         self.bg  = cv2.resize(cv2.imread("./images/template.bmp"),(226,70));
    157         self.smu = cv2.imread("./images/smu2.jpg");
    158         self.noplates_path = [];
    159         for parent,parent_folder,filenames in os.walk(NoPlates):
    160             for filename in filenames:
    161                 path = parent+"/"+filename;
    162                 self.noplates_path.append(path);
    163 
    164 
    165     def draw(self,val):
    166         offset= 2 ;
    167         self.img[0:70,offset+8:offset+8+23]= GenCh(self.fontC,val[0]);
    168         self.img[0:70,offset+8+23+6:offset+8+23+6+23]= GenCh1(self.fontE,val[1]);
    169         for i in range(5):
    170             base = offset+8+23+6+23+17 +i*23 + i*6 ;
    171             self.img[0:70, base  : base+23]= GenCh1(self.fontE,val[i+2]);
    172         return self.img
    173     
    174     def generate(self,text):
    175         if len(text) == 9:
    176             fg = self.draw(text.decode(encoding="utf-8"));
    177             fg = cv2.bitwise_not(fg);
    178             com = cv2.bitwise_or(fg,self.bg);
    179             com = rot(com,r(60)-30,com.shape,30);
    180             com = rotRandrom(com,10,(com.shape[1],com.shape[0]));
    181             com = tfactor(com)
    182             com = random_envirment(com,self.noplates_path);
    183             com = AddGauss(com, 1+r(4));
    184             com = addNoise(com);
    185             return com
    186 
    187     def genPlateString(self,pos,val):
    188         '''
    189     生成车牌String,存为图片
    190         生成车牌list,存为label
    191         '''
    192         plateStr = "";
    193         plateList=[]
    194         box = [0,0,0,0,0,0,0];
    195         if(pos!=-1):
    196             box[pos]=1;
    197         for unit,cpos in zip(box,range(len(box))):
    198             if unit == 1:
    199                 plateStr += val
    200                 #print plateStr
    201                 plateList.append(val)
    202             else:
    203                 if cpos == 0:
    204                     plateStr += chars[r(31)]
    205                     plateList.append(plateStr)
    206                 elif cpos == 1:
    207                     plateStr += chars[41+r(24)]
    208                     plateList.append(plateStr)
    209                 else:
    210                     plateStr += chars[31 + r(34)]
    211                     plateList.append(plateStr)
    212         plate = [plateList[0]]
    213         b = [plateList[i][-1] for i in range(len(plateList))]
    214         plate.extend(b[1:7])
    215         return plateStr,plate
    216 
    217     # 将生成的车牌图片写入文件夹,对应的label写入label.txt
    218     def genBatch(self, batchSize,pos,charRange, outputPath,size):
    219         if (not os.path.exists(outputPath)):
    220             os.mkdir(outputPath)
    221     outfile = open('label.txt','w')
    222         for i in xrange(batchSize):
    223                 plateStr,plate = G.genPlateString(-1,-1)
    224                 print plateStr,plate
    225         img =  G.generate(plateStr);
    226                 img = cv2.resize(img,size);
    227                 cv2.imwrite(outputPath + "/" + str(i).zfill(2) + ".jpg", img);
    228         outfile.write(str(plate)+"
    ")
    229 G = GenPlate("./font/platech.ttf",'./font/platechar.ttf',"./NoPlates")
    230 #G.genBatch(100,2,range(31,65),"./plate_100",(272,72))
    231 
    232 if __name__=='__main__':
    233     G.genBatch(int(sys.argv[1]),2,range(31,65),sys.argv[2],(272,72))
    View Code

      运行时加生成数量和保存路径即可,如:

     1 python genPlate.py 100 ./plate_100 

      显示结果:

      上图即为生成的车牌数据,有清晰的有模糊的,有比较方正的,也有一些比较倾斜,生成完大量的车牌样张后就可以进行车牌识别了。下一小节将会讲如何用端对端的CNN进行车牌识别,不需要通过传统的ocr先对字符进行分割处理后再识别。

    参考资料:

    1.原来做的车牌识别项目:https://github.com/huxiaoman7/mxnet-cnn-plate-recognition 

  • 相关阅读:
    jQuery过滤器 过滤器
    查询总结
    ado.net
    禅修程序员十诫
    Asp.net中Bind()和Eval()的区别
    什么是好代码?
    12 个有效的提高编程技能的方法
    Visual Studio各种版本之间的转换工具
    程序员的培养
    session和cookie的区别和联系!
  • 原文地址:https://www.cnblogs.com/charlotte77/p/8431077.html
Copyright © 2011-2022 走看看