使用YOLOv2和Tensorflow进行对象检测:实现

本文我们将讨论对象检测的一些关键组件(如滑动窗口,IOU,非最大抑制等)。现在,如果您对这些主题仍感到生疏,您可能需要先阅读相关内容。

注意:从网站下载YOLO V2 权重并将其放入Repo中的model_data文件夹中(https://pjreddie.com/darknet/yolo/)。

导入库:

import argparse
import os
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow
import scipy.io
import numpy as np
import scipy.misc
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 yolo_utils import read_classes,read_anchors,generate_colors,preprocess_image,draw_boxes,scale_boxes
from yad2k.model.keras_yolo import yolo_head,yolo_boxes_to_corners,preprocess_true_boxes,yolo_loss,yolo_body
sess=K.get_session()

这些是必需的Libraries。其中很多都是不言自明的。yolo_utils,这是包含帮助函数的python文件。

机器学习模型细节:

让我们先谈谈机器学习模型的输入和输出。对于这个任务,我们将使用COCO数据集(http://cocodataset.org/#home)。

输入将是一个4维向量:(m,image_height,image_width,3)。这里,m是mini-Batch size,image_height是输入图像的高度,image_width是输入图像的宽度,3是通道数。由于我们的输入是彩色图像,它有三个通道(RGB)。

对于我们的模型输出,我们将使用5个anchor boxes。现在,coco数据集包含80个类,所以如果我们谈论我们网络的输出,它将是(Px,bx,by,bh,bw,c)。现在,因为c表示类,coco包含80个类,如果我们将c表示为80维向量(第i类的第i个分量是1,其余是0),然后每个边界框将是一个85维向量,我们对一个网格的网络输出看起来像:(m,pro_image_height,pro_image_width,5,85)。这里,pro_image_height和pro_image_height是19,因为我们使用的是19×19的网格,5表示anchor boxes的数量,85表示80个类和(Px,bx,by,bh,bw)。这里需要注意的一点是,这将是一个网格的输出。这就是我们需要知道的机器学习模型。

使用YOLOv2和Tensorflow进行对象检测:实现

Output for each grid

找到Anchor Box检测到的类

因为,有80个类,我们需要找到任何一个anchor box检测到哪个类。我们只需将概率得分与网络输出的类概率相乘。

使用YOLOv2和Tensorflow进行对象检测:实现

计算类概率

过滤Anchor Boxes

现在,由于每个网格将输出5个Anchor Boxes,我们将图像分成19x19。因此,如果我们想要计算网络将输出的boxes数,它将是:19 x 19 x 5 = 1805个boxes!所以,这会让我们的输出看起来很乱,什么都不清楚。所以,如果类概率分数低于某个阈值,我们需要从输出中删除一些boxes。所以,我们将要执行过滤步骤,包括:

  • 去掉不太可能出现的boxes(Px)。
  • 执行非最大抑制。

为此,让我们创建一个函数filter_boxes,它将删除类别得分小于某个阈值(例如0.6)的boxes,Python代码如下:

def yolo_filter_boxes(box_confidence,boxes,box_class_prob,threshold=0.6):
 #box_confidence:Probabilites of containing some object
 #boxes:Size of the boxes
 #box_class_prob:containing the detection probabilites of 80 classes
 #Box scores or class probabilites
 box_scores=np.multiply(box_confidence,box_class_prob)
 #Finding the index of the class with maximum probabilities
 box_classes=K.argmax(box_scores,axis=-1)
 #Finding the value of the class with maximum probabilites
 box_class_scores=K.max(box_scores,axis=-1)
 
 filtering_mask=K.greater_equal(box_class_scores,threshold)
 #Applying the mask to scores,boxes and 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

使用YOLOv2和Tensorflow进行对象检测:实现

让我们分解此代码,逐步了解一下:

  • box-confidence:Tensor,包含一个对象(Px)的概率,其形状为(19 x 19,5,1),五个boxes由一个grid输出。。
  • boxes:Tensor,包含由单个网格输出的5个boxes中的每个框的边界框坐标(bx,by,bh,bw),其形状为(19 x 19,5,4)。
  • box_class_probs:Tensor,包含每个网格5个boxes中每个box的80个类(c1,c2,... ..c80)的检测概率,并具有形状(19 x 19,5,80)

第一步是计算类概率,这是通过元素乘以box_ confidence(Px)和box_class_prob(80个类的概率)来完成的。然后利用argmax函数求出概率最大的类的索引。然后是使用max函数的索引值。然后我们使用greater_equal函数基于box_class_score创建了一个filtering mask。最后三个步骤是对分数、类和boxes应用mask(boolean)。

非最大抑制

一旦应用过滤特定阈值(0.6)。我们仍然有class_probability大于0.6的盒子,它们可能集中在一个对象上。所以,为了克服这个问题,我们应用non_max抑制。

def yolo_non_max_suppression(scores,boxes,classes,max_boxes=10,iou_threshold=0.5):
 max_boxes_tensor=K.variable(max_boxes,dtype="int32")
 K.get_session().run(tf.variables_initializer([max_boxes_tensor]))
 
 rms_indices=tf.image.non_max_suppression(boxes,scores,max_boxes_tensor,iou_threshold=iou_threshold)
 
 scores=K.gather(scores,rms_indices)
 boxes=K.gather(boxes,rms_indices)
 classes=K.gather(classes,rms_indices)
 return scores,boxes,classes

使用YOLOv2和Tensorflow进行对象检测:实现

Scores,boxes 和classes 是filter_boxes函数的输出,max_boxes是我们想要的整数,预测框的最大数量。我们使用tf.non_max_suppression获取与我们保留的框相对应的索引列表。然后我们使用K.gather从scores,boxes 和 classes中仅选择nms_indices。

过滤框的最后一步:放在一起

现在,我们将实现yolo_eval()函数,该函数将使用我们应用的上述两个过滤函数来为我们提供单个输出。在看到代码之前,让我们再谈一个实现细节,例如,很少有representing boxes的方法,例如通过它们的角点(x1,y1,x2,y2)或者通过中点和高度/宽度。现在,我们实现的上述两个函数是用于角点表示,所以我们需要将yolo输出框转换为角点表示。其次,yolo模型在608 x 608图像上进行了训练,但是我们的数据集包含大小为720 x 1280的图像,因此我们需要一个函数来重新缩放要在720 x 1280图像上绘制的框。这两个函数都在utils中。

def yolo_eval(yolo_outputs, image_shape = (720., 1280.), max_boxes=10, score_threshold=.6, iou_threshold=.5):
 # Retrieve outputs of the YOLO model (≈1 line)
 box_confidence, box_xy, box_wh, box_class_probs = yolo_outputs
 # Convert boxes to be ready for filtering functions 
 boxes = yolo_boxes_to_corners(box_xy, box_wh)
 # Use one of the functions you've implemented to perform Score-filtering with a threshold of score_threshold (≈1 line)
 scores, boxes, classes = yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = score_threshold)
 
 # Scale boxes back to original image shape.
 boxes = scale_boxes(boxes, image_shape)
 # Use one of the functions you've implemented to perform Non-max suppression with a threshold of iou_threshold (≈1 line)
 scores, boxes, classes=yolo_non_max_suppression(scores, boxes, classes, max_boxes = max_boxes,iou_threshold=iou_threshold)
 
 return scores, boxes, classes

使用YOLOv2和Tensorflow进行对象检测:实现

实现YOLOv2

现在,yolo模型需要很长的时间来从头开始训练,所以我们将使用yolov2的权重来实现我们的第一个机器学习对象检测模型!

加载关于anchor boxes和80个类的信息

class_names = read_classes("model_data/coco_classes.txt")
anchors = read_anchors("model_data/yolo_anchors.txt")
image_shape = (720., 1280.)

加载权重:

#Loading yolo model weights
yolo_model=load_model("model_data/yolo.h5")

将模型的输出转换为可用的边界框张量:

如前所述,yolo_model的输出是(m,19,19,5,85)。因此,我们需要预处理它们,然后才能将它们用作yolo_eval函数的输入。

#As per Explained in the Blog
yolo_outputs = yolo_head(yolo_model.output, anchors, len(class_names))

下一步是应用我们的yolo_eval函数来过滤并获得最佳框。

#Applying our filtering (yolo_eval) function
scores, boxes, classes = yolo_eval(yolo_outputs, image_shape)

运行

我们已经创建了我们的图(sess)。现在,是时候定义一个函数来进行预测(在自己的图像上!)。

#Time to make prdictions 
#RUN TIME=FUN TIME!
def predict(sess, image_file):
 # Preprocess your image
 image, image_data = preprocess_image(image_file, model_image_size = (608, 608))
 # Run the session with the correct tensors and choose the correct placeholders in the feed_dict.
 # You'll need to use feed_dict={yolo_model.input: ... , K.learning_phase(): 0})
 out_scores,out_boxes,out_classes=sess.run([scores,boxes,classes],feed_dict={yolo_model.input:image_data,K.learning_phase():0})
 
 # Print predictions info
 print('Found {} boxes for {}'.format(len(out_boxes), image_file))
 # Generate colors for drawing bounding boxes.
 colors = generate_colors(class_names)
 # Draw bounding boxes on the image file
 draw_boxes(image, out_scores, out_boxes, out_classes, class_names, colors)
 # Save the predicted bounding box on the image
 image.save(os.path.join( image_file), quality=90)
 # Display the results in the notebook
 output_image = scipy.misc.imread(image_file)
 imshow(output_image)
 
 return out_scores, out_boxes, out_classes

使用YOLOv2和Tensorflow进行对象检测:实现

做出预测:

#Resizing our own Images!To be inputted to the model!!
#Before executing this cell put your image in the images folder
from PIL import Image
image=Image.open("images\ + your image file name")
image=image.resize((1280,720), Image.ANTIALIAS)
imshow(image)
image.save('images\ + your image file name')
out_scores, out_boxes, out_classes = predict(sess, "images\ + your image file name")

预测函数输出类的最终得分,最终边界框,最终类

使用YOLOv2和Tensorflow进行对象检测:实现

源码地址:https://github.com/ayu34/Object-Detection-with-YOLO-using-Tensorflow-and-Keras

相关推荐