2021SC@SDUSC
概述
接下来依旧是对SimpleRecognizePlateByE2E()函数及其内部调用的函数进行分析与总结
本篇是对delectPlateRough()函数、finemappingVertical()函数、recognizeOne()函数的分析与总结
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
首先是进行异常检测,如果top_bottom_padding_rate>0.2,会直接报错并且退出。
接着定义了三个变量。height定义为输入图片的高度,padding定义为图片高度乘top_bottom_padding_rate,显然就是图片上下部分所占实际高度,scale是定义的一个比例系数,即图片的长除以图片的高。接着对图片进行了缩放,resize函数用于对图片进行缩放,缩放后高度统一。
对图片进行裁剪,在高度这一维度上,将之前判定为上下边缘的部分裁剪掉,在长度这一维度上不进行裁剪,全部保留。padding是之前根据上下边缘占比乘以图片高度,算出来的上下边缘的实际高度,只选取图片从上边缘padding到下边缘resize_h-padding的部分,剩下的上下边缘予以舍弃。裁剪后的图片命名为image_color_cropped。
对图片进行格式转换,将刚才裁剪后的图片转换成灰度图片,这样就可以再用级联分类器进行模式识别。detectMultiScale是cv2中进行模式识别的函数,它能够对输入的图片进行识别,识别出所有待识别模式(在这里是车牌)的位置坐标和大小,将其用矩vector表示并返回,存储在watches。最后一步就是对刚才模式识别出的结果进行处理。watches中存储的x,y,w,h,分别代表识别出的车牌的横坐标、纵坐标、水平宽度、竖直高度。对刚才识别出的每个车牌都进行处理,分别修改它们的横坐标、纵坐标,并扩大它们的宽度和高度,这样就扩大了识别出车牌的边框。最后用cropImage函数对它们进行裁剪,裁剪下来的就是粗识别出的车牌的边框
modelFinemapping()函数
def model_finemapping(self):
input = Input(shape=[16, 66, 3]) # change this shape to [None,None,3] to enable arbitraty shape input
x = Conv2D(10, (3, 3), strides=1, padding='valid', name='conv1')(input)
x = Activation("relu", name='relu1')(x)
x = MaxPool2D(pool_size=2)(x)
x = Conv2D(16, (3, 3), strides=1, padding='valid', name='conv2')(x)
x = Activation("relu", name='relu2')(x)
x = Conv2D(32, (3, 3), strides=1, padding='valid', name='conv3')(x)
x = Activation("relu", name='relu3')(x)
x = Flatten()(x)
output = Dense(2,name = "dense")(x)
output = Activation("relu", name='relu4')(output)
model = Model([input], [output])
return model
首先它对输入的图片大小进行了调整,调整成为统一的大小,这样输入图片的大小就可以是任意的。接下来的部分,函数整体上就是一个卷积神经网络,它反复调用卷积(Conv2D)、激励(Activation)、池化(MaxPool2D)等函数,这说明在程序所建立的卷积神经网络中,卷积、激励和池化层都有多层并且间隔交错分布。处理完成后,最后用flatten函数对矩阵进行降维,转化为数组。
finemappingVertical()函数
def finemappingVertical(self,image,rect):
resized = cv2.resize(image,(66,16))
resized = resized.astype(np.float)/255
res_raw= self.modelFineMapping.predict(np.array([resized]))[0]
res =res_raw*image.shape[1]
res = res.astype(np.int)
H,T = res
H-=3
if H<0:
H=0
T+=2;
if T>= image.shape[1]-1:
T= image.shape[1]-1
rect[2] -= rect[2]*(1-res_raw[1] + res_raw[0])
rect[0]+=res[0]
image = image[:,H:T+2]
image = cv2.resize(image, (int(136), int(36)))
return image,rect
用modelFinemapping找出车牌左右边界的位置坐标,乘以原图的长image.shape[1],就找到了原图的车牌左右位置坐标,并分别用H,T表示。最后是输出裁剪后的图像,这样就完成了车牌精定位,精准裁剪了车牌有文字部分的左右边界之间的图像。
recognizeOne()函数
def recognizeOne(self,src):
x_tempx = src
x_temp = cv2.resize(x_tempx,( 164,48))
x_temp = x_temp.transpose(1, 0, 2)
y_pred = self.modelSeqRec.predict(np.array([x_temp]))
y_pred = y_pred[:,2:,:]
return self.fastdecode(y_pred)
的功能就是对车牌上的文字进行识别。在经历了前两个函数依次粗定位、精定位和裁剪之后,已经得到了比较精确的车牌图片,图片上只有车牌,不包含其他内容。recognizeOne输入的就是裁剪过的车牌照片,输出的是车牌上的文字。recognizeOne函数中调用的是modelSeqRec.predict函数进行预测,这个函数也是建立了一个卷积神经网络对图像进行处理,也进行了多次的卷积、激励和池化操作。此处的车牌字符信息识别不同于传统的字符识别方法,即先分割字符然后再逐一使用分类算法进行识别,而这里采用了OCR光学字符识别技术,不分割字符的前提下能够识别出车牌的七个字符。