Resumir varios pagarés y su implementación de código


Hay dos conjuntos de códigos en la parte de implementación del código, y los escenarios de uso son:
(1) Usar pagarés para examinar las muestras positivas y negativas del ancla,
(2) Calcular varios tipos de pérdidas de pagarés;

tu

inserte la descripción de la imagen aquí

gio

Sobre la base de iou, se introduce el cuadro C más pequeño que puede rodear dos cuadros,
no solo centrándose en el área superpuesta de los dos cuadros, sino también centrándose en el área no superpuesta de los dos cuadros.
inserte la descripción de la imagen aquí

hoy

inserte la descripción de la imagen aquí

por

eres oficial

Código:

(1) Calcule de forma cruzada el pagaré de las dos matrices de caja

Utilicé pytorch como el conjunto de herramientas para la implementación y organicé todo tipo de IOU en una clase, a la que se puede llamar directamente. Si tiene alguna pregunta, puede ponerla en forma de mensaje y la modificaré tan pronto como sea posible.

# ======================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) Calcular la pérdida de pagarés de la caja predicha y la caja GT

Requisito: La forma de las dos matrices de cuadro de entrada debe ser (n, 4)

Tengo tiempo para actualizar el código, no lo escribiré por el momento, por favor comprenda

La diferencia con la parte anterior del código es que al calcular la pérdida del pagaré, el hombre de regresión solo necesita calcular el pagaré con su GT ​​correspondiente, y no necesita cruzar y calcular el pagaré con el resto del GT, es decir , la entrada es dos (n, 4) y la salida es uno (n,) ; esta es la mayor diferencia con el código anterior [la entrada en el código (1) es (m, 4), (n, 4) el la salida es (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

Supongo que te gusta

Origin blog.csdn.net/weixin_50727642/article/details/125086358
Recomendado
Clasificación