赞
踩
下载本次汽车驾驶识别所需要的资料。下载地址
使用jupyter,新建文件夹,文件夹下新建一个jupyter文件,下载的相关资料也放入该文件夹中。在jupyter文件中输入以下代码。
import argparse import os import matplotlib.pyplot as plt from matplotlib.pyplot import imshow import scipy.io import scipy.misc import numpy as np import pandas as pd import PIL import tensorflow as tf from keras import backend as K from keras.layers import Input, Lambda, Conv2D from keras.models import load_model, Model from yad2k.models.keras_yolo import yolo_head, yolo_boxes_to_corners, preprocess_true_boxes, yolo_loss, yolo_body import yolo_utils
数据集是很多标记的汽车图片。pc是物体在方框内存在的置信度,c是分类,c=3是类别为汽车。
YOLO (“you only look once”)是一个很受欢迎的算法,因为它可以在实现高精度的同时能实时运行。网络仅需要进行一次正向传播便可预测,因此说该算法“仅看一次图像”。在非极大值抑制之后,模型将同边界框一起输出识别到的目标。
现在我们要为阈值进行过滤,我们要去掉一些预测值低于预设值的锚框。
模型共计会有19×19×5×85个数字,每一个锚框由85个数字组成(80个分类+ p c + p x + p y + p h + p w ),将维度为(19,19,5,85)或者(19,19,425)转换为下面的维度将会有利于我们的下一步操作:
a = np.random.randn(19x19,5,1) #p_c
b = np.random.randn(19x19,5,80) #c_1 ~ c_80
c = a * b #计算后的维度将会是(19x19,5,80)
def yolo_filter_boxes(box_confidence , boxes, box_class_probs, threshold = 0.6): """ 通过阈值来过滤对象和分类的置信度。 参数: box_confidence - tensor类型,维度为(19,19,5,1),包含19x19单元格中每个单元格预测的5个锚框中的所有的锚框的pc (一些对象的置信概率)。 boxes - tensor类型,维度为(19,19,5,4),包含了所有的锚框的(px,py,ph,pw )。 box_class_probs - tensor类型,维度为(19,19,5,80),包含了所有单元格中所有锚框的所有对象( c1,c2,c3,···,c80 )检测的概率。 threshold - 实数,阈值,如果分类预测的概率高于它,那么这个分类预测的概率就会被保留。 返回: scores - tensor 类型,维度为(None,),包含了保留了的锚框的分类概率。 boxes - tensor 类型,维度为(None,4),包含了保留了的锚框的(b_x, b_y, b_h, b_w) classess - tensor 类型,维度为(None,),包含了保留了的锚框的索引 注意:"None"是因为你不知道所选框的确切数量,因为它取决于阈值。 比如:如果有10个锚框,scores的实际输出大小将是(10,) """ #第一步:计算锚框的得分 box_scores = box_confidence * box_class_probs #第二步:找到最大值的锚框的索引以及对应的最大值的锚框的分数 box_classes = K.argmax(box_scores, axis=-1) box_class_scores = K.max(box_scores, axis=-1) #第三步:根据阈值创建掩码 filtering_mask = (box_class_scores >= threshold) #对scores, boxes 以及 classes使用掩码 scores = tf.boolean_mask(box_class_scores,filtering_mask) boxes = tf.boolean_mask(boxes,filtering_mask) classes = tf.boolean_mask(box_classes,filtering_mask) return scores , boxes , classes
测试一下
with tf.Session() as test_a:
box_confidence = tf.random_normal([19,19,5,1], mean=1, stddev=4, seed=1)
boxes = tf.random_normal([19,19,5,4], mean=1, stddev=4, seed=1)
box_class_probs = tf.random_normal([19, 19, 5, 80], mean=1, stddev=4, seed = 1)
scores, boxes, classes = yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = 0.5)
print("scores[2] = " + str(scores[2].eval()))
print("boxes[2] = " + str(boxes[2].eval()))
print("classes[2] = " + str(classes[2].eval()))
print("scores.shape = " + str(scores.shape))
print("boxes.shape = " + str(boxes.shape))
print("classes.shape = " + str(classes.shape))
test_a.close()
即使是我们通过阈值来过滤了一些得分较低的分类,但是我们依旧会有很多的锚框被留了下来,第二个过滤器就是让下图左边最终变为右边,我们叫它非最大值抑制( non-maximum suppression (NMS))
非最大值抑制使用了一个非常重要的功能,叫做交并比(Intersection over Union (IoU))
def iou(box1, box2): """ 实现两个锚框的交并比的计算 参数: box1 - 第一个锚框,元组类型,(x1, y1, x2, y2) box2 - 第二个锚框,元组类型,(x1, y1, x2, y2) 返回: iou - 实数,交并比。 """ #计算相交的区域的面积 xi1 = np.maximum(box1[0], box2[0]) yi1 = np.maximum(box1[1], box2[1]) xi2 = np.minimum(box1[2], box2[2]) yi2 = np.minimum(box1[3], box2[3]) inter_area = (xi1-xi2)*(yi1-yi2) #计算并集,公式为:Union(A,B) = A + B - Inter(A,B) box1_area = (box1[2]-box1[0])*(box1[3]-box1[1]) box2_area = (box2[2]-box2[0])*(box2[3]-box2[1]) union_area = box1_area + box2_area - inter_area #计算交并比 iou = inter_area / union_area return iou
测试一下
box1 = (2,1,4,3)
box2 = (1,2,3,4)
print("iou = " + str(iou(box1, box2)))
现在我们要实现非最大值抑制函数,关键步骤如下:
1.选择分值高的锚框
2.计算与其他框的重叠部分,并删除与iou_threshold相比重叠的框。
3.返回第一步,直到不再有比当前选中的框得分更低的框。
这将删除与选定框有较大重叠的其他所有锚框,只有得分最高的锚框仍然存在。
我们要实现的函数名为yolo_non_max_suppression(),使用TensorFlow实现,TensorFlow有两个内置函数用于实现非最大抑制(所以你实际上不需要使用你的iou()实现)
定义最大值抑制函数
def yolo_non_max_suppression(scores, boxes, classes, max_boxes=10, iou_threshold=0.5): """ 为锚框实现非最大值抑制( Non-max suppression (NMS)) 参数: scores - tensor类型,维度为(None,),yolo_filter_boxes()的输出 boxes - tensor类型,维度为(None,4),yolo_filter_boxes()的输出,已缩放到图像大小(见下文) classes - tensor类型,维度为(None,),yolo_filter_boxes()的输出 max_boxes - 整数,预测的锚框数量的最大值 iou_threshold - 实数,交并比阈值。 返回: scores - tensor类型,维度为(,None),每个锚框的预测的可能值 boxes - tensor类型,维度为(4,None),预测的锚框的坐标 classes - tensor类型,维度为(,None),每个锚框的预测的分类 注意:"None"是明显小于max_boxes的,这个函数也会改变scores、boxes、classes的维度,这会为下一步操作提供方便。 """ max_boxes_tensor = K.variable(max_boxes,dtype="int32") #用于tf.image.non_max_suppression() K.get_session().run(tf.variables_initializer([max_boxes_tensor])) #初始化变量max_boxes_tensor #使用使用tf.image.non_max_suppression()来获取与我们保留的框相对应的索引列表 nms_indices = tf.image.non_max_suppression(boxes, scores,max_boxes,iou_threshold) #使用K.gather()来选择保留的锚框 scores = K.gather(scores, nms_indices) boxes = K.gather(boxes, nms_indices) classes = K.gather(classes, nms_indices) return scores, boxes, classes
测试一下
with tf.Session() as test_b:
scores = tf.random_normal([54,], mean=1, stddev=4, seed = 1)
boxes = tf.random_normal([54, 4], mean=1, stddev=4, seed = 1)
classes = tf.random_normal([54,], mean=1, stddev=4, seed = 1)
scores, boxes, classes = yolo_non_max_suppression(scores, boxes, classes)
print("scores[2] = " + str(scores[2].eval()))
print("boxes[2] = " + str(boxes[2].eval()))
print("classes[2] = " + str(classes[2].eval()))
print("scores.shape = " + str(scores.eval().shape))
print("boxes.shape = " + str(boxes.eval().shape))
print("classes.shape = " + str(classes.eval().shape))
test_b.close()
现在我们要实现一个CNN(19x19x5x85)输出的函数,并使用刚刚实现的函数对所有框进行过滤。我们要实现的函数名为yolo_eval(),它采用YOLO编码的输出,并使用分数阈值和NMS来过滤这些框。
def yolo_eval(yolo_outputs, image_shape=(720.,1280.), max_boxes=10, score_threshold=0.6,iou_threshold=0.5): """ 将YOLO编码的输出(很多锚框)转换为预测框以及它们的分数,框坐标和类。 参数: yolo_outputs - 编码模型的输出(对于维度为(608,608,3)的图片),包含4个tensors类型的变量: box_confidence : tensor类型,维度为(None, 19, 19, 5, 1) box_xy : tensor类型,维度为(None, 19, 19, 5, 2) box_wh : tensor类型,维度为(None, 19, 19, 5, 2) box_class_probs: tensor类型,维度为(None, 19, 19, 5, 80) image_shape - tensor类型,维度为(2,),包含了输入的图像的维度,这里是(608.,608.) max_boxes - 整数,预测的锚框数量的最大值 score_threshold - 实数,可能性阈值。 iou_threshold - 实数,交并比阈值。 返回: scores - tensor类型,维度为(,None),每个锚框的预测的可能值 boxes - tensor类型,维度为(4,None),预测的锚框的坐标 classes - tensor类型,维度为(,None),每个锚框的预测的分类 """ #获取YOLO模型的输出 box_confidence, box_xy, box_wh, box_class_probs = yolo_outputs #中心点转换为边角 boxes = yolo_boxes_to_corners(box_xy,box_wh) #可信度分值过滤 scores, boxes, classes = yolo_filter_boxes(box_confidence, boxes, box_class_probs, score_threshold) #缩放锚框,以适应原始图像 boxes = yolo_utils.scale_boxes(boxes, image_shape) #使用非最大值抑制 scores, boxes, classes = yolo_non_max_suppression(scores, boxes, classes, max_boxes, iou_threshold) return scores, boxes, classes
测试一下
with tf.Session() as test_c: yolo_outputs = (tf.random_normal([19, 19, 5, 1], mean=1, stddev=4, seed = 1), tf.random_normal([19, 19, 5, 2], mean=1, stddev=4, seed = 1), tf.random_normal([19, 19, 5, 2], mean=1, stddev=4, seed = 1), tf.random_normal([19, 19, 5, 80], mean=1, stddev=4, seed = 1)) scores, boxes, classes = yolo_eval(yolo_outputs) print("scores[2] = " + str(scores[2].eval())) print("boxes[2] = " + str(boxes[2].eval())) print("classes[2] = " + str(classes[2].eval())) print("scores.shape = " + str(scores.eval().shape)) print("boxes.shape = " + str(boxes.eval().shape)) print("classes.shape = " + str(classes.eval().shape)) test_c.close()
首先创建一个会话启动计算图
sess = K.get_session()
我们试着分类80个类别,使用5个锚框。我们收集了两个文件“coco_classes.txt”和“yolo_anchors.txt”中关于80个类和5个锚框的信息。 我们将这些数据加载到模型中。
class_names = yolo_utils.read_classes("model_data/coco_classes.txt")
anchors = yolo_utils.read_anchors("model_data/yolo_anchors.txt")
image_shape = (720.,1280.)
训练YOLO模型需要很长时间,并且需要一个相当大的标签边界框数据集,用于大范围的目标类。我们将加载存储在“yolov2.h5”中的现有预训练Keras YOLO模型。 (这些权值来自官方YOLO网站,并使用Allan Zelener编写的函数进行转换,从技术上讲,这些参数来自“YOLOv2”模型。
yolo_model = load_model("model_data/yolov2.h5")
这会加载训练的YOLO模型的权重,。
yolo_model.summary()
yolo_model的输出是一个(m,19,19,5,85)的tensor变量,它需要进行处理和转换。
yolo_outputs = yolo_head(yolo_model.output, anchors, len(class_names))
yolo_outputs已经正确的格式为我们提供了yolo_model的所有预测框,我们现在已准备好执行过滤并仅选择最佳的锚框。现在让我们调用之前实现的yolo_eval()
scores, boxes, classes = yolo_eval(yolo_outputs, image_shape)
我们之前已经创建了一个用于会话的sess,这里有一些回顾:
yolo_model.input是yolo_model的输入,yolo_model.output是yolo_model的输出。
yolo_model.output会让yolo_head进行处理,这个函数最后输出yolo_outputs
yolo_outputs会让一个过滤函数yolo_eval进行处理,然后输出预测:scores、 boxes、 classes现在我们要实现predict()函数,使用它来对图像进行预测,我们需要运行TensorFlow的Session会话,然后在计算图上计算scores、 boxes、 classes,下面的代码可以帮你预处理图像:
`image, image_data = yolo_utils.preprocess_image("images/" + image_file, model_image_size = (608, 608))`
定义预测函数
def predict(sess, image_file, is_show_info=True, is_plot=True): """ 运行存储在sess的计算图以预测image_file的边界框,打印出预测的图与信息。 参数: sess - 包含了YOLO计算图的TensorFlow/Keras的会话。 image_file - 存储在images文件夹下的图片名称 返回: out_scores - tensor类型,维度为(None,),锚框的预测的可能值。 out_boxes - tensor类型,维度为(None,4),包含了锚框位置信息。 out_classes - tensor类型,维度为(None,),锚框的预测的分类索引。 """ #图像预处理 image, image_data = yolo_utils.preprocess_image("images/" + image_file, model_image_size = (608, 608)) #运行会话并在feed_dict中选择正确的占位符. out_scores, out_boxes, out_classes = sess.run([scores, boxes, classes], feed_dict = {yolo_model.input:image_data, K.learning_phase(): 0}) #打印预测信息 if is_show_info: print("在" + str(image_file) + "中找到了" + str(len(out_boxes)) + "个锚框。") #指定要绘制的边界框的颜色 colors = yolo_utils.generate_colors(class_names) #在图中绘制边界框 yolo_utils.draw_boxes(image, out_scores, out_boxes, out_classes, class_names, colors) #保存已经绘制了边界框的图 image.save(os.path.join("out", image_file), quality=100) #打印出已经绘制了边界框的图 if is_plot: output_image = scipy.misc.imread(os.path.join("out", image_file)) plt.imshow(output_image) return out_scores, out_boxes, out_classes
输入test.jpg图片进行预测
out_scores, out_boxes, out_classes = predict(sess, "test.jpg")
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。