深度学习|2D目标检测|锚框实现和IoU计算

本文是在李沐老师的d2l课程的基础上,对提供的多锚框实现和IoU计算代码进行逐步解释(注释),当作备忘。

课程和代码地址:13.4. 锚框 — 动手学深度学习 2.0.0 documentation (d2l.ai)

一、锚框实现

锚框的定义不再赘述,本质上也是bbox的一种从采样角度的表达方式。这里需要注意的是,以同一像素为中心的锚框的数量是n+m-1。对于整个输入图像,将共生成wh(n+m-1)个锚框。其中w h m n分别为宽、高、宽高比数量、缩放比数量。

首先,定义多锚框函数如下:

def multibox_prior(data, sizes, ratios):
    """生成以每个像素为中心具有不同形状的锚框"""

其中data大小为(batch_size, chanel, height, width),sizes和ratios分别为人为设定的缩放比和宽高比,大小为(1, n)和(1, m)。

接着是数据提取和转换:

# 读取data后两位作为图片输入的高、宽:
    in_height, in_width = data.shape[-2:]
# 指定设备、获取m、n:
    device, num_sizes, num_ratios = data.device, len(sizes), len(ratios)
#计算每一个像素的锚框数量(n+m-1):
    boxes_per_pixel = (num_sizes + num_ratios - 1)
#将输入的数组转化为tensor:
    size_tensor = torch.tensor(sizes, device=device)
    ratio_tensor = torch.tensor(ratios, device=device)

对于每一个像素生成锚框中心:

    # 为了将锚点移动到像素的中心,需要设置偏移量。
    # 因为一个像素的高为1且宽为1,我们选择偏移我们的中心0.5
    offset_h, offset_w = 0.5, 0.5

    steps_h = 1.0 / in_height  # 在y轴上缩放步长
    steps_w = 1.0 / in_width  # 在x轴上缩放步长

    # 生成锚框的所有中心点
    # 这里在每一个center的相对位置(相对于图像左上角的位置)都除以了总长度,因此后面我们的输出要乘以长度来恢复
    center_h = (torch.arange(in_height, device=device) + offset_h) * steps_h
    center_w = (torch.arange(in_width, device=device) + offset_w) * steps_w

    # mesgrid生成大小为(h, w)的输出
    shift_y, shift_x = torch.meshgrid(center_h, center_w, indexing='ij')
    # 拉平偏移量
    shift_y, shift_x = shift_y.reshape(-1), shift_x.reshape(-1)

然后根据锚框高、宽计算公式,计算每个像素对应的锚框大小:

    # 生成“boxes_per_pixel”个高和宽,
    # 之后用于创建锚框的四角坐标(xmin,xmax,ymin,ymax)
    w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),
                   sizes[0] * torch.sqrt(ratio_tensor[1:])))\
                   * in_height / in_width  # 处理矩形输入
    h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]),
                   sizes[0] / torch.sqrt(ratio_tensor[1:])))
    # 除以2来获得半高和半宽
    # 这里repeat相当于作用在每一个像素上,一共是h*w个像素
    anchor_manipulations = torch.stack((-w, -h, w, h)).T.repeat(
                                        in_height * in_width, 1) / 2

最后,把锚框中心和manipulation相加得到四角坐标:

    # 每个中心点都将有“boxes_per_pixel”个锚框,
    # 所以生成含所有锚框中心的网格,重复了“boxes_per_pixel”次(n+m-1)
    # 其中堆叠的[x, y, x, y]就对应加上[-w, -h, w, h]/2得到四角坐标
    out_grid = torch.stack([shift_x, shift_y, shift_x, shift_y],
                dim=1).repeat_interleave(boxes_per_pixel, dim=0)
    output = out_grid + anchor_manipulations
    return output.unsqueeze(0)

输出output结果大小是(batch_size, 全部anchor的数量, 4),其中最后一维就是(xmin,xmax,ymin,ymax)。

二、IoU的计算

交并比示意图如下(图源d2l.ai)

显然,根据几何推理,对于两个不同像素产生的锚框,其2个锚框之间的IoU只需要求出两个框各自的面积和相交面积即可。我们假设某情况下box1落在box2的左上:

则IoU的计算可以表达为:\frac{Inter_{12}}{Aera_1+Area_2-Inter{12}},其中Inter_{12}=(x_{1,max}-x_{2,min})(y_{1,max}-y_{2,min})。这里需要注意,图像定义的坐标原点为左上角。

回到代码,先定义IoU函数的输入boxes为指定像素位置的锚框组成的tensor,并求出各自的面积:

def box_iou(boxes1, boxes2):
    """计算两个锚框或边界框列表中成对的交并比"""
# boxes第1维是编号,第2维是四角坐标,提取四角坐标用于计算每一个box的面积:
    box_area = lambda boxes: ((boxes[:, 2] - boxes[:, 0]) *
                              (boxes[:, 3] - boxes[:, 1]))
    # boxes1,boxes2,areas1,areas2的形状:
    # boxes1:(boxes1的数量,4),
    # boxes2:(boxes2的数量,4),
    # areas1:(boxes1的数量,),
    # areas2:(boxes2的数量,)
# 计算面积:
    areas1 = box_area(boxes1)
    areas2 = box_area(boxes2)

然后计算分子和分母,进而得到IoU,需要注意维度的变换和切片:

    # inter_upperlefts,inter_lowerrights,inters的形状:
    # (boxes1的数量,boxes2的数量,2)
    # 这里使用了None来占位,tensor从后往前对齐,目的是为了组合两个box的编号形成inter的前2维:
    inter_upperlefts = torch.max(boxes1[:, None, :2], boxes2[:, :2])
    inter_lowerrights = torch.min(boxes1[:, None, 2:], boxes2[:, 2:])
    inters = (inter_lowerrights - inter_upperlefts).clamp(min=0)  # clamp()规定了inter最小值是0,防止没有交集时分子是负数的情况
    # inter_areas and union_areas的形状:(boxes1的数量,boxes2的数量)
    inter_areas = inters[:, :, 0] * inters[:, :, 1]
    union_areas = areas1[:, None] + areas2 - inter_areas
    return inter_areas / union_areas

这样就可以实现pixel_wise的IoU计算。

(不足之处,还请指出~)

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值