总结各类IOU以及其代码实现


代码实现部分有两套代码,使用场景分别是:
(1)使用iou对anchor进行正负样本的筛选;
(2)计算各类的iou损失;

iou

在这里插入图片描述

giou

在iou的基础上引入了能够包围两个box的最小框C,
不仅关注两个box的重叠区域,还关注两个框的非重叠区域
在这里插入图片描述

diou

在这里插入图片描述

ciou

ciou公式

代码实现:

(1)交叉计算两个box矩阵的iou

使用过了pytorch作为实现的工具包,将各类iou整理成一个类,可以直接调用这个类,其中有问题大家可以用留言的形式提出来,我会尽快修改

# ======================IoU类========================#
# 计算各类IoU,Tensor格式
# ======================IoU类========================#
class IoU:
    types = ("iou", "giou", "diou", "ciou", "eiou")

    def __init__(self, iou_type="iou"):
        assert iou_type in self.types, "iou_type ERROR, iou_type must in %s" % str(self.types)
        self.iou_type = iou_type

    def __call__(self, bbox1: torch.Tensor, bbox2: torch.Tensor, is_center=True, eps=1e-7):
        """

        :param bbox1: (n, 4)或者(4, )
        :param bbox2: (m, 4)或者(4, )
        :param is_center: 输入坐标的格式。True:Center;False:Corner
        :return: ious:(n, m)
        """
        CHANGE = False
        dim_ = -1
        # ==============================================#
        # 统一bbox的格式
        # ==============================================#
        corner1 = torch.zeros_like(bbox1)
        corner2 = torch.zeros_like(bbox2)
        if is_center:
            # center -> corner
            corner1[..., 0] = bbox1[..., 0] - bbox1[..., 2] / 2
            corner1[..., 1] = bbox1[..., 1] - bbox1[..., 3] / 2
            corner1[..., 2] = bbox1[..., 0] + bbox1[..., 2] / 2
            corner1[..., 3] = bbox1[..., 1] + bbox1[..., 3] / 2

            corner2[..., 0] = bbox2[..., 0] - bbox2[..., 2] / 2
            corner2[..., 1] = bbox2[..., 1] - bbox2[..., 3] / 2
            corner2[..., 2] = bbox2[..., 0] + bbox2[..., 2] / 2
            corner2[..., 3] = bbox2[..., 1] + bbox2[..., 3] / 2
        else:
            corner1 = bbox1
            corner2 = bbox2
        # ==============================================#
        # 维度统一,
        # 将输入的维度统一为2维
        # 只有当dim为1时CHANGE = True;
        # 有如下几种情况:
        #   corner1:(4, )->(1, 4);corner2:(m, 4);->(1, 4)->(4, )
        #   corner1:(n, 4);corner2:(4, )->(1, 4);->(n, 1)->(n, )
        #   corner1:(4, )->(1, 4);corner2:(4, )->(1, 4);->(1, 1)->(1, )
        # ==============================================#
        if corner1.ndim < 2:
            CHANGE = True
            dim_ = 0
            corner1 = corner1.unsqueeze(dim=0)
        elif corner1.dim() > 2:
            raise ValueError("corner1.dim() should be equal 2.")

        if corner2.dim() < 2:
            CHANGE = True
            dim_ = 1
            corner2 = corner2.unsqueeze(dim=0)
        elif corner2.ndim > 2:
            raise ValueError("corner1 dim should be equal 2.")

        if self.iou_type is self.types[0]:  # iou
            iou = self._iou(corner1, corner2, eps=eps)
            if CHANGE:
                iou = torch.squeeze(iou, dim=dim_)
            return iou

        elif self.iou_type is self.types[1]:  # giou
            giou = self._giou(corner1, corner2, eps=eps)
            if CHANGE:
                giou = torch.squeeze(giou, dim=dim_)
            return giou

        elif self.iou_type is self.types[2]:  # diou
            diou = self._diou(corner1, corner2, eps=eps)
            if CHANGE:
                diou = torch.squeeze(diou, dim=dim_)
            return diou
        elif self.iou_type is self.types[3]:  # ciou
            ciou = self._ciou(corner1, corner2, eps=eps)
            if CHANGE:
                ciou = torch.squeeze(ciou, dim=dim_)
            return ciou

        elif self.iou_type is self.types[4]:  # eiou
            pass

    @staticmethod
    def _iou(corner1: torch.Tensor, corner2: torch.Tensor, eps=1e-7) -> torch.Tensor:
        """

        :param corner1:(n, 4)
        :param corner2:(m ,4)
        :return:(n, m)
        """
        # 记录边界框的个数
        num_box1 = corner1.shape[0]
        num_box2 = corner2.shape[0]

        # ----------------------计算交集的对角坐标----------------------开始-#
        # 两个box的右下角中 数值小 的就是交集的右下角坐标,输出的维度为:(n, m, 2)
        # 维度变化:(n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2)
        inter_bottom_right = torch.min(torch.unsqueeze(corner1[..., 2:], dim=1).expand(num_box1, num_box2, 2),
                                       torch.unsqueeze(corner2[..., 2:], dim=0).expand(num_box1, num_box2, 2))

        # 两个box的左上角中 数值大 的就是交集的左上角坐标,输出的维度为:(n, m, 2)
        # 维度变化:(n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2)
        inter_top_left = torch.max(torch.unsqueeze(corner1[..., 0:2], dim=1).expand(num_box1, num_box2, 2),
                                   torch.unsqueeze(corner2[..., 0:2], dim=0).expand(num_box1, num_box2, 2))
        # (n, m, 2)
        inter_wh = torch.clamp((inter_bottom_right - inter_top_left), min=0)
        # 交集:(n, m)
        inter = inter_wh[..., 0] * inter_wh[..., 1]
        # ----------------------计算交集的对角坐标----------------------结束-#

        # ----------------------计算bbox的面积----------------------开始-#
        # (n, )
        area_corner1 = (corner1[..., 2] - corner1[..., 0]) * (corner1[..., 3] - corner1[..., 1])
        # (n, )->(n, 1)->(n, m)
        area_corner1 = torch.unsqueeze(area_corner1, dim=1).expand_as(inter)

        # (m, )
        area_corner2 = (corner2[..., 2] - corner2[..., 0]) * (corner2[..., 3] - corner2[..., 1])
        # (m, )->(1, m)->(n, m)
        area_corner2 = torch.unsqueeze(area_corner2, dim=0).expand_as(inter)
        # ----------------------计算bbox的面积----------------------结束-#

        # ----------------------计算交并比----------------------开始-#
        # 交集:(n, m)
        union = area_corner1 + area_corner2 - inter + eps
        # iou:(n, m)
        iou = inter / union
        # ----------------------计算交并比----------------------结束-#
        return iou

    @staticmethod
    def _giou(corner1: torch.Tensor, corner2: torch.Tensor, eps=1e-7) -> torch.Tensor:
        """
        在预测框和真实框没有很好的对齐时,会导致最小外界框C的面积增大,
        从而使GIOU的值变小,而两个矩形框不重合时,也可以计算GIoU。
        GIoU Loss虽然解决了IOU的问题,但是产生的新bug就是当两个框属于包含关系是,GIoU无法区分其相对位置.
        由于GIoU仍然严重依赖于IoU,因此在两个垂直方向,误差很大,基本很难收敛,这就是GIoU不稳定的原因。
        :param corner1: (n, 4)
        :param corner2: (m, 4)
        :return: d iou:(n, m)
        """
        # 记录box个数
        num_box1 = corner1.shape[0]
        num_box2 = corner2.shape[0]

        # ----------------------包围两个box的最小边界框----------------------开始-#
        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2);
        c_union_bottom_right = torch.max(torch.unsqueeze(corner1[..., 2:], dim=1).expand(num_box1, num_box2, 2),
                                         torch.unsqueeze(corner2[..., 2:], dim=0).expand(num_box1, num_box2, 2))

        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2);
        c_union_top_left = torch.min(torch.unsqueeze(corner1[..., 0:2], dim=1).expand(num_box1, num_box2, 2),
                                     torch.unsqueeze(corner2[..., 0:2], dim=0).expand(num_box1, num_box2, 2))
        # (n, m, 2)
        c_union_wh = torch.clamp((c_union_bottom_right - c_union_top_left), min=0)
        # (n, m)
        area_c = c_union_wh[..., 0] * c_union_wh[..., 1] + eps
        # ----------------------包围两个box的最小边界框----------------------结束-#

        # ----------------------计算两个box的交集----------------------开始-#
        #  (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2);
        inter_bottom_right = torch.min(torch.unsqueeze(corner1[..., 2:], dim=1).expand(num_box1, num_box2, 2),
                                       torch.unsqueeze(corner2[..., 2:], dim=0).expand(num_box1, num_box2, 2))
        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2);
        inter_top_left = torch.max(torch.unsqueeze(corner1[..., 0:2], dim=1).expand(num_box1, num_box2, 2),
                                   torch.unsqueeze(corner2[..., 0:2], dim=0).expand(num_box1, num_box2, 2))
        # (n, m, 2)
        inter_wh = torch.clamp((inter_bottom_right - inter_top_left), min=0)
        # (n, m)
        inter = inter_wh[..., 0] * inter_wh[..., 1]
        # ----------------------计算两个box的交集----------------------结束-#

        # ----------------------两个box的面积----------------------开始-#
        # (n, )
        area_corner1 = (corner1[..., 2] - corner1[..., 0]) * (corner1[..., 3] - corner1[..., 1])
        # (n, )->(n, 1)->(n, m)
        area_corner1 = torch.unsqueeze(area_corner1, dim=1).expand_as(inter)

        # (m, )
        area_corner2 = (corner2[..., 2] - corner2[..., 0]) * (corner2[..., 3] - corner2[..., 1])
        # (m, )->(1, m)->(n, m)
        area_corner2 = torch.unsqueeze(area_corner2, dim=0).expand_as(inter)
        # ----------------------两个box的面积----------------------结束-#

        # ======================计算IOU======================#
        union = area_corner1 + area_corner2 - inter + eps
        iou = inter / union

        giou = iou - (area_c - union) / area_c
        return giou

    @staticmethod
    def _diou(corner1: torch.Tensor, corner2: torch.Tensor, eps=1e-7) -> torch.Tensor:
        """
        DIoU Loss的惩罚项能够直接最小化中心点间的距离,而且GIoU Loss旨在减少外界包围框的面积
        DIoU与IoU,GIoU一样具有尺度不变性
        DIoU与GIoU一样在与目标框不重叠时,仍然可以为边界框提供移动方向
        DIoU可以直接最小化两个目标框的距离,因此比GIoU Loss 收敛快得多
        DIoU在包含两个水平或垂直方向上的情况回归很快,而GIoU几乎退化为IoU

        :param corner1:(n, 4)
        :param corner2:(m, 4)
        :return:(n, m)
        """
        # 记录边box个数
        num_box1 = corner1.shape[0]
        num_box2 = corner2.shape[0]

        # ----------------------计算包围两个box最小的框C----------------------开始-#
        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2)
        c_union_bottom_right = torch.max(torch.unsqueeze(corner1[..., 2:], dim=1).expand(num_box1, num_box2, 2),
                                         torch.unsqueeze(corner2[..., 2:], dim=0).expand(num_box1, num_box2, 2))

        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2)
        c_union_top_left = torch.min(torch.unsqueeze(corner1[..., 0:2], dim=1).expand(num_box1, num_box2, 2),
                                     torch.unsqueeze(corner2[..., 0:2], dim=0).expand(num_box1, num_box2, 2))

        # (n, m, 2)
        c_union_wh = torch.clamp((c_union_bottom_right - c_union_top_left), min=0)
        # (n, m)
        c_union_diagonal2 = c_union_wh[..., 0] ** 2 + c_union_wh[..., 1] ** 2
        # ----------------------计算包围两个box最小的框C----------------------结束-#

        # ----------------------计算交集----------------------开始-#
        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2)
        inter_bottom_right = torch.min(torch.unsqueeze(corner1[..., 2:], dim=1).expand(num_box1, num_box2, 2),
                                       torch.unsqueeze(corner2[..., 2:], dim=0).expand(num_box1, num_box2, 2))

        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2)
        inter_top_left = torch.max(torch.unsqueeze(corner1[..., 0:2], dim=1).expand(num_box1, num_box2, 2),
                                   torch.unsqueeze(corner2[..., 0:2], dim=0).expand(num_box1, num_box2, 2))
        # (n, m, 2)
        inter_wh = torch.clamp((inter_bottom_right) - inter_top_left, min=0)
        # (n, m)
        inter = inter_wh[..., 0] * inter_wh[..., 1]
        # ----------------------计算交集----------------------结束-#

        # ----------------------计算两个box的中心点之间的欧氏距离的平方----------------------开始-#
        # corner1的中心点坐标:(n, 2)->(n, 1, 2)->(n, m, 2)
        center1_xy = torch.unsqueeze((corner1[..., 2:] + corner1[..., 0:2]) / 2, dim=1).expand(num_box1, num_box2, 2)
        # corner2的中心点坐标:(m, 2)->(1, m, 2)->(n, m, 2)
        center2_xy = torch.unsqueeze((corner2[..., 2:] + corner2[..., 0:2]) / 2, dim=0).expand(num_box1, num_box2, 2)
        # (n, m)
        center_distance2 = (center2_xy[..., 0] - center1_xy[..., 0]) ** 2 + \
                           (center2_xy[..., 1] - center1_xy[..., 1]) ** 2
        # ----------------------计算两个box的中心点之间的欧氏距离的平方----------------------结束-#

        # ----------------------计算两个box的并集----------------------开始-#
        # (n, )
        area_corner1 = (corner1[..., 2] - corner1[..., 0]) * (corner1[..., 3] - corner1[..., 1])
        # (n, )->(n, 1)->(n, m)
        area_corner1 = torch.unsqueeze(area_corner1, dim=1).expand_as(inter)

        # (m, )
        area_corner2 = (corner2[..., 2] - corner2[..., 0]) * (corner2[..., 3] - corner2[..., 1])
        # (m, )->(1, m)->(n, m)
        area_corner2 = torch.unsqueeze(area_corner2, dim=0).expand_as(inter)
        # ----------------------计算两个box的并集----------------------结束-#

        # ======================计算diou======================#
        # (n, m)
        union = area_corner1 + area_corner2 - inter

        iou = inter / (union + eps)

        diou = iou - center_distance2 / (c_union_diagonal2 + eps)
        return diou

    @staticmethod
    def _ciou(corner1: torch.Tensor, corner2: torch.Tensor, eps=1e-7) -> torch.Tensor:
        """
        CIoU Loss和DIoU Loss的区别在于CIoU考虑了Bounding box的纵横比,进一步提升了回归进度。
        CIoU的惩罚项是DIoU的惩罚基础上加了一个影响因子 , 这个因子把预测框纵横比拟合真实框的纵横比考虑进去。
        :param corner1:
        :param corner2:
        :return:
        """
        # 记录box的个数
        num_box1 = corner1.shape[0]
        num_box2 = corner2.shape[0]

        # ----------------------计算包围两个box最小的框C----------------------开始-#
        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2)
        c_union_bottom_right = torch.max(torch.unsqueeze(corner1[..., 2:], dim=1).expand(num_box1, num_box2, 2),
                                         torch.unsqueeze(corner2[..., 2:], dim=0).expand(num_box1, num_box2, 2))
        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2)
        c_union_top_left = torch.min(torch.unsqueeze(corner1[..., 0:2], dim=1).expand(num_box1, num_box2, 2),
                                     torch.unsqueeze(corner2[..., 0:2], dim=0).expand(num_box1, num_box2, 2))
        # (n, m, 2)
        c_union_wh = torch.clamp(c_union_bottom_right - c_union_top_left, min=0)
        # (n, m)
        c_union_diagonal2 = c_union_wh[..., 0] ** 2 + c_union_wh[..., 1] ** 2
        # ----------------------计算包围两个box最小的框C----------------------结束-#

        # ----------------------计算交集----------------------开始-#
        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2)
        inter_bottom_right = torch.min(torch.unsqueeze(corner1[..., 2:], dim=1).expand(num_box1, num_box2, 2),
                                       torch.unsqueeze(corner2[..., 2:], dim=0).expand(num_box1, num_box2, 2))
        # (n, 2)->(n, 1, 2)->(n, m, 2);(m, 2)->(1, m, 2)->(n, m, 2)
        inter_top_left = torch.max(torch.unsqueeze(corner1[..., 0:2], dim=1).expand(num_box1, num_box2, 2),
                                   torch.unsqueeze(corner2[..., 0:2], dim=0).expand(num_box1, num_box2, 2))
        # (n, m, 2)
        inter_wh = torch.clamp(inter_bottom_right - inter_top_left, min=0)
        # (n, m)
        inter = inter_wh[..., 0] * inter_wh[..., 1]
        # ----------------------计算交集----------------------结束-#

        # ----------------------计算box的面积----------------------开始-#
        # (n, )
        area_corner1 = (corner1[..., 2] - corner1[..., 0]) * (corner1[..., 3] - corner1[..., 1])
        # (n, )->(n, 1)->(n, m)
        area_corner1 = torch.unsqueeze(area_corner1, dim=1).expand_as(inter)
        # (m, )
        area_corner2 = (corner2[..., 2] - corner2[..., 0]) * (corner2[..., 3] - corner2[..., 1])
        # (m, )->(1, m)->(n, m)
        area_corner2 = torch.unsqueeze(area_corner2, dim=0).expand_as(inter)
        # ----------------------计算box的面积----------------------结束-#

        # ----------------------计算iou----------------------开始-#
        union = area_corner1 + area_corner2 - inter
        iou = inter / (union + eps)
        # ----------------------计算iou----------------------结束-#

        # ----------------------计算纵横比惩罚项----------------------开始-#
        # box1的wh:(n, 2)->(n, 1, 2)->(n, m, 2)
        box1_wh = torch.unsqueeze(corner1[..., 2:] - corner1[..., 0:2], dim=1).expand(num_box1, num_box2, 2)
        # box1的wh:(n, 2)->(n, 1, 2)->(n, m, 2)
        box2_wh = torch.unsqueeze(corner2[..., 2:] - corner2[..., 0:2], dim=0).expand(num_box1, num_box2, 2)
        # 衡量长宽比一致性的参数v:(n, m)
        vv = (torch.arctan(box1_wh[..., 0] / box1_wh[..., 1]) - torch.arctan(box2_wh[..., 0] / box2_wh[..., 1])) ** 2
        v = 4 * vv / (math.pi ** 2)
        # 用于做trade-off的参数alpha
        alpha = v / (1 - iou + v + eps)
        # ----------------------计算纵横比惩罚项----------------------结束-#

        # ----------------------计算两个box的中心点距离平方----------------------开始-#
        # (n, 2)->(n, 1, 2)->(n, m, 2)
        corner1_xy = torch.unsqueeze((corner1[..., 2:] + corner1[..., 0:2]) / 2, dim=1).expand(num_box1, num_box2, 2)
        # (m, 2)->(1, m, 2)->(n, m, 2)
        corner2_xy = torch.unsqueeze((corner2[..., 2:] + corner2[..., 0:2]) / 2, dim=0).expand(num_box1, num_box2, 2)
        # (n, m)
        center_distance2 = (corner2_xy[..., 0] - corner1_xy[..., 0]) ** 2 + \
                           (corner2_xy[..., 1] - corner1_xy[..., 1]) ** 2
        # ----------------------计算连个box的中心点距离平方----------------------结束-#

        # ======================计算ciou======================#
        ciou = iou - center_distance2 / (c_union_diagonal2 + eps) - alpha * v
        return ciou

(2)计算预测box和GT box的iou损失

要求:输入的两个box矩阵shape必须都是(n, 4)

有时间更新代码,暂时不写,敬请谅解

以上一部分代码不同之处在于,计算iou损失时,回归狂只需要和自己对应的GT计算iou就行,不需要交叉和其余的GT计算iou,即输入是两个(n, 4)输出是一个(n, );这是与上面代码最大的不同 [代码(1)中输入是(m, 4), (n, 4)输出是(m, n)]

# ======================IoU Loss类========================#
# 计算个类IoU Loss
# ======================IoU Loss类========================#
class IouLoss:
    types = ("iou_loss", "giou_loss", "diou_loss", "ciou_loss", "eiou_loss")

    def __init__(self, loss_type="iou_loss"):
        assert loss_type in self.types, "iou_type ERROR, iou_type must in %s" % str(self.types)
        self.loss_type = loss_type

    def __call__(self, bbox1: torch.Tensor, bbox2: torch.Tensor, is_center=True, eps=1e-7):
        """

        :param bbox1: (n, 4)
        :param bbox2: (n, 4)
        :param is_center:
        :return:
        """
        assert bbox1.shape == bbox2.shape, "The shape of bbox1 and bbox2 must be consistent."
        # ==============================================#
        # 统一bbox的格式
        # ==============================================#
        corner1 = torch.zeros_like(bbox1)
        corner2 = torch.zeros_like(bbox2)
        if is_center:
            # center -> corner
            corner1[..., 0] = bbox1[..., 0] - bbox1[..., 2] / 2
            corner1[..., 1] = bbox1[..., 1] - bbox1[..., 3] / 2
            corner1[..., 2] = bbox1[..., 0] + bbox1[..., 2] / 2
            corner1[..., 3] = bbox1[..., 1] + bbox1[..., 3] / 2

            corner2[..., 0] = bbox2[..., 0] - bbox2[..., 2] / 2
            corner2[..., 1] = bbox2[..., 1] - bbox2[..., 3] / 2
            corner2[..., 2] = bbox2[..., 0] + bbox2[..., 2] / 2
            corner2[..., 3] = bbox2[..., 1] + bbox2[..., 3] / 2
        else:
            corner1 = bbox1
            corner2 = bbox2
        if self.loss_type == self.types[0]:  # iou loss
            loss = self._iou_loss(corner1, corner2, eps=eps)
            return loss
        elif self.loss_type == self.types[1]:  # giou loss
            loss = self._giou_loss(corner1, corner2, eps=eps)
            return loss
        elif self.loss_type == self.types[2]:  # diou loss
            loss = self._diou_loss(corner1, corner2, eps=eps)
            return loss
        elif self.loss_type == self.types[3]:  # ciou loss
            loss = self._ciou_loss(corner1, corner2, eps=eps)
            return loss
        elif self.loss_type == self.types[4]:  # eiou loss
            print("敬请期待...")

    @staticmethod
    def _iou_loss(corner1, corner2, eps=1e-7) -> torch.Tensor:
        """

        :param corner1: (n ,4)
        :param corner2: (n ,4)
        :return:
        """
        # ----------------------计算交集----------------------开始-#
        # (n, 2)
        inter_bottom_right = torch.min(corner1[:, 2:], corner2[:, 2:])
        # (n, 2)
        inter_top_left = torch.max(corner1[:, :2], corner2[:, :2])
        # (n ,2)
        inter_wh = torch.clamp((inter_bottom_right - inter_top_left), min=0)
        # 交集:(n, )
        inter = inter_wh[:, 0] * inter_wh[:, 1]
        # ----------------------计算交集----------------------结束-#

        # ----------------------计算box的面积----------------------开始-#
        # (n, )
        area_corner1 = (corner1[:, 2] - corner1[:, 0]) * (corner1[:, 3] - corner1[:, 1])
        # (n, )
        area_corner2 = (corner2[:, 2] - corner2[:, 0]) * (corner2[:, 3] - corner2[:, 1])
        # ----------------------计算box的面积----------------------结束-#

        # ----------------------计算交并比----------------------开始-#
        # 交集:(n, )
        union = area_corner1 + area_corner2 - inter + eps
        # (n, )
        ious = inter / union
        # ----------------------计算交并比----------------------结束-#
        # (n, )
        loss = 1 - ious
        return loss

    @staticmethod
    def _giou_loss(corner1: torch.Tensor, corner2: torch.Tensor, eps=1e-7) -> torch.Tensor:
        """

        :param corner1:
        :param corner2:
        :return:
        """
        # ----------------------计算交集----------------------开始-#
        # (n, 2)
        inter_bottom_right = torch.min(corner1[:, 2:], corner2[:, 2:])
        # (n, 2)
        inter_top_left = torch.max(corner1[:, :2], corner2[:, :2])
        # (n ,2)
        inter_wh = torch.clamp((inter_bottom_right - inter_top_left), min=0)
        # 交集:(n, )
        inter = inter_wh[:, 0] * inter_wh[:, 1]
        # ----------------------计算交集----------------------结束-#

        # ----------------------计算box的面积----------------------开始-#
        # (n, )
        area_corner1 = (corner1[:, 2] - corner1[:, 0]) * (corner1[:, 3] - corner1[:, 1])
        # (n, )
        area_corner2 = (corner2[:, 2] - corner2[:, 0]) * (corner2[:, 3] - corner2[:, 1])
        # ----------------------计算box的面积----------------------结束-#

        # ----------------------计算交并比----------------------开始-#
        # 交集:(n, )
        union = area_corner1 + area_corner2 - inter + eps
        # (n, )
        ious = inter / union
        # ----------------------计算交并比----------------------结束-#

        # ----------------------计算最小包围框C----------------------开始-#
        # (n ,2)
        c_union_bottom_right = torch.max(corner1[:, 2:], corner2[:, 2:])
        # (n ,2)
        c_union_top_left = torch.min(corner1[:, :2], corner2[:, :2])
        # (n, 2)
        c_union_wh = torch.clamp((c_union_bottom_right - c_union_top_left), min=0)
        # (n, )
        area_c = c_union_wh[:, 0] * c_union_wh[:, 1] + eps
        # ----------------------计算最小包围框C----------------------结束-#
        giou = ious - (area_c - union) / area_c
        # (n, )
        loss = 1 - giou
        return loss

    @staticmethod
    def _diou_loss(corner1: torch.Tensor, corner2: torch.Tensor, eps=1e-7) -> torch.Tensor:
        """

        :param corner1:
        :param corner2:
        :return:
        """
        # ----------------------计算交集----------------------开始-#
        # (n, 2)
        inter_bottom_right = torch.min(corner1[:, 2:], corner2[:, 2:])
        # (n, 2)
        inter_top_left = torch.max(corner1[:, :2], corner2[:, :2])
        # (n ,2)
        inter_wh = torch.clamp((inter_bottom_right - inter_top_left), min=0)
        # 交集:(n, )
        inter = inter_wh[:, 0] * inter_wh[:, 1]
        # ----------------------计算交集----------------------结束-#

        # ----------------------计算box的面积----------------------开始-#
        # (n, )
        area_corner1 = (corner1[:, 2] - corner1[:, 0]) * (corner1[:, 3] - corner1[:, 1])
        # (n, )
        area_corner2 = (corner2[:, 2] - corner2[:, 0]) * (corner2[:, 3] - corner2[:, 1])
        # ----------------------计算box的面积----------------------结束-#

        # ----------------------计算交并比----------------------开始-#
        # 交集:(n, )
        union = area_corner1 + area_corner2 - inter
        # (n, )
        ious = inter / (union + eps)
        # ----------------------计算交并比----------------------结束-#

        # ----------------------计算最小包围框C----------------------开始-#
        # (n ,2)
        c_union_bottom_right = torch.max(corner1[:, 2:], corner2[:, 2:])
        # (n ,2)
        c_union_top_left = torch.min(corner1[:, :2], corner2[:, :2])
        # (n, 2)
        c_union_wh = torch.clamp((c_union_bottom_right - c_union_top_left), min=0)
        # (n, ):使用勾股定理计算对角线长度
        c_union_diagonal2 = c_union_wh[:, 0] ** 2 + c_union_wh[:, 1] ** 2
        # ----------------------计算最小包围框C----------------------结束-#

        # ----------------------计算两个box中心点之间的距离----------------------开始-#
        # (n, 2)
        center1_xy = (corner1[:, 2:] + corner1[:, :2]) / 2
        # (n ,2)
        center2_xy = (corner2[:, 2:] + corner2[:, :2]) / 2
        # (n ,2)
        distance_xy = center2_xy - center1_xy
        # (n, )
        center_distance2 = distance_xy[:, 0] ** 2 + distance_xy[:, 1] ** 2 + eps
        # ----------------------计算两个box中心点之间的距离----------------------结束-#

        diou = ious - center_distance2 / c_union_diagonal2
        # (n, )
        loss = 1 - diou
        return loss

    @staticmethod
    def _ciou_loss(corner1: torch.Tensor, corner2: torch.Tensor, eps=1e-7) -> torch.Tensor:
        """

        :param corner1:
        :param corner2:
        :return:
        """
        # ----------------------计算交集----------------------开始-#
        # (n, 2)
        inter_bottom_right = torch.min(corner1[:, 2:], corner2[:, 2:])
        # (n, 2)
        inter_top_left = torch.max(corner1[:, :2], corner2[:, :2])
        # (n ,2)
        inter_wh = torch.clamp((inter_bottom_right - inter_top_left), min=0)
        # 交集:(n, )
        inter = inter_wh[:, 0] * inter_wh[:, 1]
        # ----------------------计算交集----------------------结束-#

        # ----------------------计算box的面积----------------------开始-#
        # (n, )
        area_corner1 = (corner1[:, 2] - corner1[:, 0]) * (corner1[:, 3] - corner1[:, 1])
        # (n, )
        area_corner2 = (corner2[:, 2] - corner2[:, 0]) * (corner2[:, 3] - corner2[:, 1])
        # ----------------------计算box的面积----------------------结束-#

        # ----------------------计算交并比----------------------开始-#
        # 交集:(n, )
        union = area_corner1 + area_corner2 - inter
        # (n, )
        ious = inter / (union + eps)
        # ----------------------计算交并比----------------------结束-#

        # ----------------------计算最小包围框C----------------------开始-#
        # (n ,2)
        c_union_bottom_right = torch.max(corner1[:, 2:], corner2[:, 2:])
        # (n ,2)
        c_union_top_left = torch.min(corner1[:, :2], corner2[:, :2])
        # (n, 2)
        c_union_wh = torch.clamp((c_union_bottom_right - c_union_top_left), min=0)
        # (n, ):使用勾股定理计算对角线长度
        c_union_diagonal2 = c_union_wh[:, 0] ** 2 + c_union_wh[:, 1] ** 2
        # ----------------------计算最小包围框C----------------------结束-#

        # ----------------------计算两个box中心点之间的距离----------------------开始-#
        # (n, 2)
        center1_xy = (corner1[:, 2:] + corner1[:, :2]) / 2
        # (n ,2)
        center2_xy = (corner2[:, 2:] + corner2[:, :2]) / 2
        # (n ,2)
        distance_xy = center2_xy - center1_xy
        # (n, )
        center_distance2 = distance_xy[:, 0] ** 2 + distance_xy[:, 1] ** 2
        # ----------------------计算两个box中心点之间的距离----------------------结束-#

        # ----------------------计算宽高比惩罚项----------------------开始-#
        # (n, 2)
        wh1 = corner1[:, 2:] - corner1[:, :2]
        # (n ,2)
        wh2 = corner2[:, 2:] - corner2[:, :2]
        # 衡量长宽比一致醒的参数:(n, )
        v = ((torch.arctan(wh1[:, 0] / wh1[:, 1]) - torch.arctan(wh2[:, 0] / wh2[:, 1])) * 2 / math.pi) ** 2
        alpha = v / (1 - ious + v + eps)

        # ----------------------计算宽高比惩罚项----------------------结束-#

        ciou = ious - center_distance2 / (c_union_diagonal2 + eps) - alpha * v
        # (n, )
        loss = 1 - ciou
        return loss

猜你喜欢

转载自blog.csdn.net/weixin_50727642/article/details/125086358