深度学习

【转载】车辆检测识别(YOLOV2)

2018-05-14  本文已影响13人  dopami

https://zhuanlan.zhihu.com/p/36795627

基于YOLOV2-tiny实现车辆检测:

代码地址:yang1688899/Vehicle-Detection-YOLO-keras

YOLO简介:

YOLO意为 You Only Look Once,是一种基于深度学习的端对端(end to end)物体检测方法.与R-CNN,Fast-R-CNN,Faster-R-CNN等通过region proposal产生大量的可能包含待检测物体的 potential bounding box,再用分类器去判断每个 bounding box里是否包含有物体,以及物体所属类别的方法不同,YOLO将物体检测任务当做一个regression问题来处理.

YOLO检测思路:

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

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

每个栅格负责预测5个bounding box(bounding box包括中心点坐标x,y及其宽w,高h,共4个值)。对于每个bounding box预测其是否包含物体的confidence score(1个值),及其所包含物体class的possibility分布(由于有20个class,这里有20个值)。最终模型的的输出为13x13x125.这里13x13对应13x13个栅格(grid cell).每个bounding box 一共有4+1+20=25个值,每个栅格检测5个bounding box,则有每个栅格对应5x25=125个值,因此13x13x125.

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

模型最终检测到13x13x5=845个bounding box把所有的bounding box都画到原图上可能会是这样子的:

大多数的bounding box 的confidence score都是非常低的(也就是没有检测到物体的),只要少数的bounding box 是高confidence score的,检测到物体的。通过confidence score与最大的class的possibility相乘可以得到该bounding box 包含某物体的置信度,对这一置信度进行阈值过滤可以把大部分无意义的bounding box过滤掉。剩下的bounding box 可能存在的多重检测问题(即一个物体被多个bounding box检测)可以用NMS,heatmap等方法进行过滤整合,得到最终检测结果。

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

实现步骤

ps:本来是打算keras构建模型结构,然后加载weights文件训练后了参数实现的,但一直没有搞清楚weights文件的参数是怎么和模型各层对应上,最后找了YAD2K,里面提供了把YOLOV2 weights文件直接转换成keras model文件的方法,就直接拿来用了。

使用YAD2K把weights文件转化为keras的h5文件

使用model预测bounding box

阈值筛选bounding box

使用YAD2K把weights文件转化为keras的h5文件

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

weight文件下载;

获得YAD2K;

运行yad2k.py文件,参数依次为:cfg文件路径,weights文件路径,model文件输出路径.

这里使用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 function,用于在预测时生成指定batch_size大小的图片batch:

#prediction_generatordef 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。 为了方便对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及是否包含物体的confidence score和其所包含物体class的possibility,其中中心点坐标x,y及其宽w,高h都是相对于每个栅格(grid cell)而言的,因此这些参数都需要进行转换。使用confidence score与最大的class的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进行过滤(ps:也可以使用车辆识别(特征提取+svm分类器)中介绍的heatmap进行过滤,只要达到使每个物体对应一个合适的bounding box的目的):

#使用non_maxsuppression 筛选boxdef 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展示在图片上,以下为示例代码:

#在图片上画出boxdef 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

结果:

编辑于 昨天 16:58

计算机视觉

深度学习(Deep Learning)

Keras

上一篇下一篇

猜你喜欢

热点阅读