Directorio de artículos
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
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.
hoy
por
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