HyperLPR源码分析3

2021SC@SDUSC

根据小组分配到的任务,我将负责HyperLPRLite.py中SimpleRecognizePlateByE2E(self,image)函数的分析。

该函数的代码如下:

 def SimpleRecognizePlateByE2E(self,image):
        images = self.detectPlateRough(image,image.shape[0],top_bottom_padding_rate=0.1)
        res_set = []
        for j,plate in enumerate(images):
            plate, rect  =plate
            image_rgb,rect_refine = self.finemappingVertical(plate,rect)
            res,confidence = self.recognizeOne(image_rgb)
            res_set.append([res,confidence,rect_refine])
        return res_set

一、函数总览

    SimpleRecognizePlateByE2E(self,image)函数是对车牌号进行识别的核心函数,它的算法思路是这样的:

(1)、对导入的车牌文件(也就是图片)进行车牌粗定位,目的是找出图中所有的车牌,这部分是通过delectPlateRough函数实现的。

(2)、找出所有车牌后,对图中所有车牌进行精定位,也就是沿着这些车牌的轮廓,将车牌裁剪下来,方便接下来对车牌内容进行识别,这项功能是通过finemappingVertical函数实现的。

(3)、最后要对车牌进行文字识别,通过recognizeOne函数实现

二、detectPlateRough函数

images = self.detectPlateRough(image,image.shape[0],top_bottom_padding_rate=0.1)

     这条语句的作用就是将图片进行车牌粗定位,找到图中所有车牌的大致位置。image.shape[]是Python内置的数组,其定义如下:

image.shape[0] 图片高

image.shape[1] 图片长(水平长度)

image.shape[2] 图片通道数。(灰度图的通道数为1,因为描述灰度图中的每个像素点只需要一个数值,而彩色图通道数为3,因为描述每个像素点都需要RGB三个值。)

    top_bottom_padding_rate用来描述要进行粗定位的图片,其上下部分占整体图片的比例,这里直接默认为0.1

    下面是detectPlateRough函数的代码:

    def detectPlateRough(self,image_gray,resize_h = 720,en_scale =1.08 ,top_bottom_padding_rate = 0.05):
        if top_bottom_padding_rate>0.2:
            print("error:top_bottom_padding_rate > 0.2:",top_bottom_padding_rate)
            exit(1)
        height = image_gray.shape[0]
        padding =    int(height*top_bottom_padding_rate)
        scale = image_gray.shape[1]/float(image_gray.shape[0])
        image = cv2.resize(image_gray, (int(scale*resize_h), resize_h))
        image_color_cropped = image[padding:resize_h-padding,0:image_gray.shape[1]]
        image_gray = cv2.cvtColor(image_color_cropped,cv2.COLOR_RGB2GRAY)
        watches = self.watch_cascade.detectMultiScale(image_gray, en_scale, 2, minSize=(36, 9),maxSize=(36*40, 9*40))
        cropped_images = []
        for (x, y, w, h) in watches:
            x -= w * 0.14
            w += w * 0.28
            y -= h * 0.15
            h += h * 0.3
            cropped = self.cropImage(image_color_cropped, (int(x), int(y), int(w), int(h)))
            cropped_images.append([cropped,[x, y+padding, w, h]])
        return cropped_images

(1)、首先是进行异常检测,如果top_bottom_padding_rate>0.2,会直接报错并且退出。

 if top_bottom_padding_rate>0.2:
            print("error:top_bottom_padding_rate > 0.2:",top_bottom_padding_rate)
            exit(1)

(2)、接着定义了三个变量。height定义为输入图片的高度,padding定义为图片高度乘top_bottom_padding_rate,显然就是图片上下部分所占实际高度,scale是定义的一个比例系数,即图片的长除以图片的高

 height = image_gray.shape[0]
 padding =    int(height*top_bottom_padding_rate)
 scale = image_gray.shape[1]/float(image_gray.shape[0])

(3)、接着对图片进行了缩放,resize函数用于对图片进行缩放。缩放后图片的高统一为720(在函数最开头已经将resize_h设为720)

 image = cv2.resize(image_gray, (int(scale*resize_h), resize_h))

(4)、对图片进行裁剪,在高度这一维度上,将之前判定为上下边缘的部分裁剪掉,在长度这一维度上不进行裁剪,全部保留。padding是之前根据上下边缘占比乘以图片高度,算出来的上下边缘的实际高度,只选取图片从上边缘padding到下边缘resize_h-padding的部分,剩下的上下边缘予以舍弃。裁剪后的图片命名为image_color_cropped。

      介绍一下裁剪的实现原理。图片是以像素点形式,通过二维数组存储的,第一个维度代表图片的垂直高度,第二个维度代表图片的水平长度。“:”表示对一个维度的数组进行切片,m:n表示对这个数组从m开始到n的部分进行切片,即只保留m到n的部分,舍弃剩下的部分。在该代码段,就是对高度这个维度,只保留从padding到resize_h-padding,也就是从上边缘到下边缘,在长度这个维度,则是从0保留到image_gray.shape[1],在前面已经提到过,这个数值表示图片的长度,也就是长度这个维度是全部保留的。将图片的两个二维数组进行切片后保存在image_color_cropped这个新图片里,这个新图片就是对原图片的裁剪。

image_color_cropped = image[padding:resize_h-padding,0:image_gray.shape[1]]

(5)、对图片进行格式转换,将刚才裁剪后的图片转换成灰度图片。cvtColor是cv2的颜色空间转换函数,用法是cvtColor(p1,p2),p1是要转换的图片,p2是要转换成的格式。cv2.RGB2GRAY表示把RGB图片转换成灰度图。

 image_gray = cv2.cvtColor(image_color_cropped,cv2.COLOR_RGB2GRAY)

(6)、接着就用级联分类器进行模式识别。detectMultiScale是cv2中进行模式识别的函数,它能够对输入的图片进行识别,识别出所有待识别模式(在这里是车牌)的位置坐标和大小,将其用矩vector表示并返回,存储在watches

  watches = self.watch_cascade.detectMultiScale(image_gray, en_scale, 2, minSize=(36, 9),maxSize=(36*40, 9*40))

(7)、最后一步就是对刚才模式识别出的结果进行处理。watches中存储的x,y,w,h,分别代表识别出的车牌的横坐标、纵坐标、水平宽度、竖直高度。对刚才识别出的每个车牌都进行处理,分别修改它们的横坐标、纵坐标,并扩大它们的宽度和高度,这样就扩大了识别出车牌的边框。最后用cropImage函数对它们进行裁剪,裁剪下来的就是粗识别出的车牌的边框。

 for (x, y, w, h) in watches:
            x -= w * 0.14
            w += w * 0.28
            y -= h * 0.15
            h += h * 0.3
            cropped = self.cropImage(image_color_cropped, (int(x), int(y), int(w), int(h)))
            cropped_images.append([cropped,[x, y+padding, w, h]])
        return cropped_images

三、任务展望

    在下周的分析中,我将对finemappingVertical函数进行分析。

你可能感兴趣的:(python,人工智能)