Object Detection

Concept and Principle

目标检测任务与图像分类不同,目标检测要在图片中识别出多个不同的目标并表明每个目标的位置

  • 边缘框

    • 边缘框表示了目标的位置,有两种坐标表示法
      • (左上x,左上y,右下x,右下y)
      • (左上x,左上y,边框宽,边框高)
  • 锚框

    • 锚框在目标检测算法中很常用,许多目标检测算法都用到了这项技术
    • 锚框是对边缘框的一个猜测:
      • 提出多个被称为锚框的区域
      • 预测每个锚框中是否含有目标物体
      • 如果有,则继续预测从这个锚框到真实边缘框的偏移
    • 使用交并比(IoU)来计算两个框的相似度(预测框和标签框)
    • 赋予锚框标号
      • 在训练时,每个锚框都是一个训练样本,每次读取一张图片都要进行一次赋予锚框标号的操作
      • 将每个锚框要么标注为背景,要么标注为与真实边缘框相关
      • 可能生成大量锚框导致负样本过多
      • 锚框可固定生成,或根据图片生成,甚至随机
      • 假设一个图片有4个标签边缘框,生成了9个锚框,一种赋予标号的算法如下图
    • 在预测时,使用非极大值抑制(NMS)输出
  • 目标检测常用算法

    1. Faster R-CNN
      图片进入一个CNN后分成两条路线,一条路线进入RPN(负责生成锚框),另一条路线经过RoI pooling(将不同大小的锚框提取为同一大小)后连接至全连接层,最后做出分类以及边缘框预测。Faster R-CNN相对其他算法来说还是很慢,但精度很高,适合刷榜。

    2. SSD(单发多框检测)
      SSD由一个基础的网络来抽取特征,然后多个卷积层块来减半高宽。每段都会生成锚框,底部段拟合小物体,顶部段拟合大物体。每个锚框都会预测类别和边缘框

    3. YOLO
      SSD中锚框有大量重叠,YOLO将图片均匀分成SxS个锚框,每个锚框预测B个边缘框。

Implementation

  • 边缘框实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    import torch
    from PIL import Image
    from matplotlib import pyplot as plt

    img=Image.open("./1.jpg")
    plt.imshow(img)
    plt.show()
    fig=plt.imshow(img)


    def box_corner_to_center(boxes):
    """(左上,右下)转换到(中间,宽度,高度)

    Args:
    boxs : 一组边缘框
    """
    x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
    cx = (x1 + x2) / 2
    cy = (y1 + y2) / 2
    w = x2 - x1
    h = y2 - y1
    # 将新坐标堆叠起来变为二维Tensor,注意与cat不同
    boxes = torch.stack((cx, cy, w, h))
    # 返回转置
    return boxes.T

    def box_center_to_corner(boxes):
    """(中间,宽度,高度)转换到(左上,右下)

    Args:
    boxs : 一组边缘框
    """
    cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
    x1 = cx - 0.5 * w
    y1 = cy - 0.5 * h
    x2 = cx + 0.5 * w
    y2 = cy + 0.5 * h
    boxes = torch.stack((x1, y1, x2, y2))
    return boxes.T

    x=torch.tensor([[0., 0., 2., 2.]])
    x=box_corner_to_center(x)
    print(x)
    x=box_center_to_corner(x)
    print(x)


    box1=torch.tensor([360,170,650,650])
    box2=torch.tensor([120,210,350,290])



    def show_bboxes(fig,bboxes,color):
    """显示带边缘框的图片

    """
    for b,c in zip(bboxes,color):
    fig.axes.add_patch(_bbox_to_rect(b, c))
    plt.show()

    def _bbox_to_rect(bbox, color):
    return plt.Rectangle(xy=(bbox[0], bbox[1]), width=bbox[2] - bbox[0],
    height=bbox[3] - bbox[1], fill=False,
    edgecolor=color, linewidth=2)



    show_bboxes(fig,[box1,box2],['red','green'])