目标检测是计算机视觉领域的一项重要应用。通过目标检测模型,能将图片中的人、汽车等目标物体检测出来。

一个简单的目标标签y如下:

其中,$b_{x}$、$b_{y}$ 表示汽车中点, $b_{h}$、$b_{w}$ 表示定位框的高和宽。当 $P_{c}=1$ 时,表示图片中存在目标物体,反之表示图片中不存在物体,此时不再关心y的其他值为多少,这些值也不会参数损失函数的计算。

滑动窗口

目标检测采用基于滑动窗口的检测算法。此方法计算成本较大,且有许多重复的运算。目前可以使用卷积层实现滑动窗口,不需要将输入图片分割成多个子集分别执行前向传播,而是把它们作为一张图片输入到卷积神经网络中进行计算,其中的重叠部分可以共享大量的计算。

用卷积方式实现滑动窗口,可使计算效率大大提高,但存在的问题是不能输出最精准的边界框。YOLO算法可以使得滑动窗口算法寻找到更加精准的边界框。此算法将图片分割成多个格子,观察每个对象的中点,将该对象分配到其中点所在的格子中。

交并比

交并比函数用来评价目标检测算法是否运作良好。

$$ IoU = 交集面积 / 并集面积 $$

一般在目标检测任务中,约定如果$IoU\geqslant0.5$,说明检测正确。

def iou(box1, box2):
    """
    参数:
    box1 -- 第一个边界框, 坐标 (x1, y1, x2, y2)
    box2 -- 第二个边界框, 坐标 (x1, y1, x2, y2)
    """
    # 计算交集
    xi1 = max(box1[0], box2[0])
    yi1 = max(box1[1], box2[1])
    xi2 = min(box1[2], box2[2])
    yi2 = min(box1[3], box2[3])
    inter_area = (yi2 - yi1) * (xi2 - xi1)
    # 计算并集,公式:Union(A,B) = A + B - Inter(A,B)
    box1_area = (box1[3] - box1[1]) * (box1[2] - box1[0])
    box2_area = (box2[3] - box2[1]) * (box2[2] - box2[0])
    union_area = box1_area + box2_area - inter_area
    # 计算IoU
    iou = inter_area / union_area
    return iou

非极大值抑制

目标检测算法可能会对同一个对象做出多次检测,非极大值抑制可以确保模型对每个对象只检测一次,其对多种检测结果进行清理,选取最大$P_{c}$的边界框,对其他具有高交并比的边界框进行抑制。

首先,我们需要清除那些分数低(差的检测)的边界框。

def yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = .6):
    # 计算每个边界框的分数,用box_confidence(边界框的含有目标的置信概率)乘以box_class_probs(边界框对每个类别的检测概率)。
    box_scores = box_confidence * box_class_probs
    # 找到各个分数最大值所属的类别和值
    box_classes = K.argmax(box_scores, axis=-1)
    box_class_scores = K.max(box_scores, axis=-1, keepdims=False)
    # 通过阈值创建一个mask(掩码),决定需保留的边界框
    filtering_mask = box_class_scores >= threshold
    # 根据掩码更新各参数
    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

当几个边界框相互重叠并且检测到的是同一个对象时,只选择一个边界框。

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]))
    # 使用TensorFlow内置的函数实现非极大值抑制,输入边界框(box)和最大边界框,scores为边界框的概率分数P,返回要保留的数据的索引
    nms_indices = tf.image.non_max_suppression(boxes, scores, max_boxes, iou_threshold)
    # 根据索引选出边界框及相关数据
    scores = K.gather(scores, nms_indices)
    boxes = K.gather(boxes, nms_indices)
    classes = K.gather(classes, nms_indices)
    return scores, boxes, classes

Anchor box

预先定义多个不同形状的Anchor box,把预测目标和对应的Anchor box关联起来,从而实现多个重叠对象的检测。

候选区域

在图片中选出一些目标的候选区域,从而避免传统滑动窗口在大量无对象区域的无用运算。使用了R-CNN后,仅在少数窗口上运行卷积网络。