Advertisement

车辆检测识别(YOLOV2)

阅读量:

YOLO(You Only Look Once)是一种基于深度学习的端到端物体检测方法,与传统方法通过区域建议生成器(R-CNN、Fast/R-CNN、Faster/R-CNN)不同,YOLO将检测任务视为回归问题,直接预测物体的边界框及其置信度和类别概率。其工作原理如下:将输入图像划分为13x13个栅格,每个栅格负责预测5个边界框,每个边界框包含中心坐标、宽高、置信度和类别概率。YOLO通过将检测结果与非极大值抑制(NMS)结合,实现物体检测。实现步骤包括使用YAD2K将YOLO权重文件转换为Keras模型文件,对视频进行预测,并对预测结果进行阈值筛选和NMS处理。最终输出的检测结果包括物体类别、置信度和边界框坐标。

该方法在性能上显著优于asio,这得益于其简单的设计和简洁的代码。代码地址:yang1688899/Vehicle-Detection-YOLO-keras

YOLO简介:

YOLO源自You Only Look Once,是一种基于深度学习的端到端(end-to-end)物体检测方法。不同于基于region proposal的方法,YOLO将物体检测任务建模为一个回归问题来处理,避免了生成大量潜在的bounding box并逐一分类的繁琐过程。

YOLO检测思路:

(这里以输入为416x416的YOLOV2为例)

首先将图片划分为13x13个栅格(grid cell):

每个栅格负责处理5个bounding box,每个bounding box包含中心点坐标x,y及其宽w、高h(共4个参数),并判断是否包含物体的置信分数(1个值)以及所属物体类别的概率分布(20个类别,共20个值)。最终模型输出为13x13x125,其中13x13对应13x13个栅格(grid cell)。每个bounding box总计4+1+20=25个值,每个栅格检测5个bounding box,因此每个栅格对应5x25=125个值,最终输出为13x13x125。

以下为每个栅格的对应输出:

该模型识别出13×13×5=845个bounding box,将所有bounding box绘制在原始图像上可能会呈现出以下效果:

大多数bounding box的confidence score较低(即未检测到物体),只有少数bounding box具有较高的confidence score,意味着物体被检测到。通过将confidence score与所属类别的最大可能性相乘,可以计算出该bounding box包含特定物体的置信度。通过设置阈值,可以有效去除大部分无意义的bounding box。对于剩下的bounding box,可能需要使用NMS、热图等方法来解决多重检测问题,最终获得准确的检测结果。

经过过滤处理的检测结果会是这样的:

实现步骤

原本计划是使用Keras构建模型结构,并通过加载weights文件来迁移训练后的参数实现项目,但始终不清楚weights文件中的参数是如何与模型各层对应起来的。最后,我参考了YAD2K的相关介绍,了解到可以通过该库将YOLOV2 weights文件直接转换为Keras model文件的方法,并将其直接应用于项目中。

利用YAD2K工具将weights文件转换为Keras的h5格式模型文件。
通过模型预测bounding box的位置。
设置阈值筛选出有效的bounding box。

通过YAD2K将weights文件转换为keras的h5文件。

下载相应的YOLO weights和cfg文件:

权重文件下载直达链接:https://link.zhihu.com/?target=https%3A//pjreddie.com/darknet/yolov2/

权重文件下载直达链接:https://link.zhihu.com/?target=https%3A//pjreddie.com/darknet/yolov2/

访问YAD2K代码库,官方GitHub链接为:官方GitHub链接

请执行yad2k.py脚本,其参数依次为配置文件路径、权重文件路径以及模型输出路径。

这里使用yolov2-tiny模型的voc版本,运行如下命令:

复制代码
    python ./yad2k.py ./yolov2-tiny-voc.cfg ./yolov2-tiny-voc.weights ./model/yolov2-tiny-voc.h5

使用model预测bounding box

举个例子,这里是一个在Keras中,predict_generator方法用于对视频进行预测的示例。在内存和显存充足的条件下,可以直接调用predict方法。

首先使用opencv读取视频,并进行resize,normalize等预处理:

复制代码
 #把给定视频转换为图片

    
 def preprocess_video(src_path):
    
     cap = cv2.VideoCapture(src_path)
    
     num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    
     fps = int(cap.get(cv2.CAP_PROP_FPS))
    
     fourcc = int(cap.get(cv2.CAP_PROP_FOURCC))
    
     video_frames = []
    
     for i in range(num_frames):
    
     ret, frame = cap.read()
    
     if ret:
    
         frame = cv2.resize(frame, (416, 416))
    
         frame = preprocess_image(frame)
    
         video_frames.append(frame)
    
     video_frames = np.array(video_frames)
    
     cap.release()
    
     return video_frames,num_frames,fps,fourcc

通过yield实现一个generator函数,用于生成图片并设置batch_size大小,在预测时使用。

复制代码
 #prediction_generator

    
 def video_batch_gen(video_frames,batch_size=32):
    
    for offset in range(0,len(video_frames),batch_size):
    
    yield video_frames[offset:offset+batch_size]

最后加载model,使用predict_generator进行预测:

复制代码
 video_frames, num_frames, fps, fourcc = utils.preprocess_video(src_path)

    
 gen = utils.video_batch_gen(video_frames,batch_size=batch_size)
    
  
    
 model = load_model("./model/yolov2-tiny-voc.h5")
    
  
    
 print("predicting......")
    
 predictions = model.predict_generator(gen)

阈值筛选bounding box

获得 predictions 后,还需对 predictions 进行进一步的处理,其目的是去除置信度较低的 bounding box 和重叠的 bounding box,以确保每张图片中的每一个物体都对应一个置信度最高的 bounding box。为了更方便地对 predictions 进行处理,这里定义了一个 box 类来存储 bounding box 的参数:

复制代码
 class Box:

    
     def __init__(self):
    
     self.w = float()
    
     self.h = float()
    
     self.p_max = float()
    
     self.clas = int()
    
     self.x1 = int()
    
     self.y1 = int()
    
     self.x2 = int()
    
     self.y2 = int()

模型预测bounding box的中心点坐标x和y,以及宽度w和高度h,这些参数均基于每个栅格进行计算。其中,中心点坐标x和y,以及宽度w和高度h均基于每个栅格进行计算。因此,这些参数需要经过转换处理。通过将confidence score与最大类别的possibility相乘,可以得到置信度分数。对置信度进行阈值筛选,可以有效去除置信度较低的bounding box候选。

复制代码
 prediction = np.reshape(prediction, (n_grid, n_grid, n_box, 5+n_class))

    
 boxes = []
    
 for row in range(n_grid):
    
     for col in range(n_grid):
    
     for b in range(n_box):
    
         tx, ty, tw, th, tc = prediction[row, col, b, :5]
    
         box = Box()
    
  
    
         box.w = np.exp(tw) * anchors[2 * b + 0] * 32.0
    
         box.h = np.exp(th) * anchors[2 * b + 1] * 32.0
    
  
    
         c_probs = softmax(prediction[row, col, b, 5:])
    
         box.clas = np.argmax(c_probs)
    
         box.p_max = np.max(c_probs) * sigmoid(tc)
    
  
    
         center_x = (float(col) + sigmoid(tx)) * 32.0
    
         center_y = (float(row) + sigmoid(ty)) * 32.0
    
  
    
         box.x1 = int(center_x - (box.w / 2.))
    
         box.x2 = int(center_x + (box.w / 2.))
    
         box.y1 = int(center_y - (box.h / 2.))
    
         box.y2 = int(center_y + (box.h / 2.))
    
  
    
         if box.p_max > probs_threshold:
    
             boxes.append(box)

经过初步处理后的bounding box仍会有大量重叠的情况:

以下采用非极大值抑制(NMS)对bounding box进行筛选处理,注:也可以使用车辆识别技术(基于特征提取与SVM分类器)进行过滤,只要能够确保每个物体对应一个合适的bounding box。

复制代码
 #使用non_maxsuppression 筛选box

    
 def non_maximal_suppression(thresholded_boxes, iou_threshold=0.3):
    
     nms_boxes = []
    
     if len(thresholded_boxes) > 0:
    
     # 添加置信度最高的box
    
     nms_boxes.append(thresholded_boxes[0])
    
  
    
     i = 1
    
     while i < len(thresholded_boxes):
    
         n_boxes_to_check = len(nms_boxes)
    
         to_delete = False
    
  
    
         j = 0
    
         while j < n_boxes_to_check:
    
             curr_iou = iou(thresholded_boxes[i], nms_boxes[j])
    
             if (curr_iou > iou_threshold):
    
                 to_delete = True
    
             j = j + 1
    
  
    
         if to_delete == False:
    
             nms_boxes.append(thresholded_boxes[i])
    
         i = i + 1
    
  
    
     return nms_boxes

最后把过滤后的bounding box展示在图片上,以下为示例代码:

复制代码
 #在图片上画出box

    
 def draw_boxes(image,boxes):
    
     for i in range(len(boxes)):
    
     color = colors[boxes[i].clas]
    
     best_class_name = classes[boxes[i].clas]
    
  
    
     image = cv2.rectangle(image, (boxes[i].x1, boxes[i].y1),
    
                                 (boxes[i].x2, boxes[i].y2),color)
    
  
    
     cv2.putText(
    
         image, best_class_name + ' : %.2f' % boxes[i].p_max,
    
         (int(boxes[i].x1 + 5), int(boxes[i].y1 - 7)), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
    
         color, 1)
    
  
    
     return image

结果:

全部评论 (0)

还没有任何评论哟~