YOLOv6-4.0部分代码阅读笔记-figure_iou.py

news/2024/11/8 17:16:10 标签: YOLO, 笔记, python

figure_iou.py

yolov6\utils\figure_iou.py

目录

figure_iou.py

1.所需的库和模块

2.class IOUloss: 

3.def pairwise_bbox_iou(box1, box2, box_format='xywh'): 


1.所需的库和模块

python">#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import math
import torch

2.class IOUloss: 

python">class IOUloss:
    # 计算IoU损失。
    """ Calculate IoU loss.
    """
    # reduction :这个参数指定了在计算损失或评估指标时如何处理多个值。 'none' 表示不对值进行任何特殊处理,即不进行求和、平均或最大/最小值计算。其他的值包括 'mean' (平均值)、 'sum' (总和)等,这些值影响如何聚合多个损失或指标值。
    def __init__(self, box_format='xywh', iou_type='ciou', reduction='none', eps=1e-7):
        # 类别的设置。
        """ Setting of the class.
        Args:
            box_format: (string), must be one of 'xywh' or 'xyxy'.    必须是“xywh”或“xyxy”之一。
            iou_type: (string), can be one of 'ciou', 'diou', 'giou' or 'siou'    可以是“ciou”、“diou”、“giou”或“siou”之一。
            reduction: (string), specifies the reduction to apply to the output, must be one of 'none', 'mean','sum'.    指定应用于输出的缩减,必须是“none”、“mean”、“sum”之一。
            eps: (float), a value to avoid divide by zero error.    一个避免被零错误除的值。
        """
        self.box_format = box_format
        self.iou_type = iou_type.lower()
        self.reduction = reduction
        self.eps = eps

    def __call__(self, box1, box2):
        # 计算 iou 。 box1 和 box2 是形状为[M, 4]和[Nm 4]的torch张量。
        """ calculate iou. box1 and box2 are torch tensor with shape [M, 4] and [Nm 4].
        """
        if box1.shape[0] != box2.shape[0]:
            box2 = box2.T
            if self.box_format == 'xyxy':
                b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]
                b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]
            elif self.box_format == 'xywh':
                b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2
                b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2
                b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2
                b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2
        else:
            if self.box_format == 'xyxy':
                b1_x1, b1_y1, b1_x2, b1_y2 = torch.split(box1, 1, dim=-1)
                b2_x1, b2_y1, b2_x2, b2_y2 = torch.split(box2, 1, dim=-1)

            elif self.box_format == 'xywh':
                b1_x1, b1_y1, b1_w, b1_h = torch.split(box1, 1, dim=-1)
                b2_x1, b2_y1, b2_w, b2_h = torch.split(box2, 1, dim=-1)
                b1_x1, b1_x2 = b1_x1 - b1_w / 2, b1_x1 + b1_w / 2
                b1_y1, b1_y2 = b1_y1 - b1_h / 2, b1_y1 + b1_h / 2
                b2_x1, b2_x2 = b2_x1 - b2_w / 2, b2_x1 + b2_w / 2
                b2_y1, b2_y2 = b2_y1 - b2_h / 2, b2_y1 + b2_h / 2

        # Intersection area    交叉区域
        # torch.clamp(input, min, max, out=None) → Tensor
        # clamp() 函数的功能将输入 input 张量每个元素的值压缩到区间 [min,max],并返回结果到一个新张量。
        # input :输入张量。
        # min :限制范围下限。
        # max :限制范围上限。
        # out :输出张量。

        # pytorch中,一般来说如果对tensor的一个函数后加上了下划线,则表明这是一个 in-place 类型。
        # in-place 类型是指,当在一个tensor上操作了之后,是直接修改了这个tensor,而不是返回一个新的tensor并不修改旧的tensor。

        inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
                (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)

        # Union Area    联合区域
        w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + self.eps
        w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + self.eps
        union = w1 * h1 + w2 * h2 - inter + self.eps
        iou = inter / union

        cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1)  # convex width    外接矩形的宽度
        ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1)  # convex height    外接矩形的高度
        if self.iou_type == 'giou':
            c_area = cw * ch + self.eps  # convex area
            iou = iou - (c_area - union) / c_area
        elif self.iou_type in ['diou', 'ciou']:
            c2 = cw ** 2 + ch ** 2 + self.eps  # convex diagonal squared
            rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 +
                    (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4  # center distance squared
            if self.iou_type == 'diou':
                iou = iou - rho2 / c2
            elif self.iou_type == 'ciou':
                v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2)
                with torch.no_grad():
                    alpha = v / (v - iou + (1 + self.eps))
                iou = iou - (rho2 / c2 + v * alpha)
        elif self.iou_type == 'siou':
            # SIoU Loss https://arxiv.org/pdf/2205.12740.pdf
            s_cw = (b2_x1 + b2_x2 - b1_x1 - b1_x2) * 0.5 + self.eps
            s_ch = (b2_y1 + b2_y2 - b1_y1 - b1_y2) * 0.5 + self.eps
            sigma = torch.pow(s_cw ** 2 + s_ch ** 2, 0.5)
            sin_alpha_1 = torch.abs(s_cw) / sigma
            sin_alpha_2 = torch.abs(s_ch) / sigma
            threshold = pow(2, 0.5) / 2
            sin_alpha = torch.where(sin_alpha_1 > threshold, sin_alpha_2, sin_alpha_1)
            angle_cost = torch.cos(torch.arcsin(sin_alpha) * 2 - math.pi / 2)
            rho_x = (s_cw / cw) ** 2
            rho_y = (s_ch / ch) ** 2
            gamma = angle_cost - 2
            distance_cost = 2 - torch.exp(gamma * rho_x) - torch.exp(gamma * rho_y)
            omiga_w = torch.abs(w1 - w2) / torch.max(w1, w2)
            omiga_h = torch.abs(h1 - h2) / torch.max(h1, h2)
            shape_cost = torch.pow(1 - torch.exp(-1 * omiga_w), 4) + torch.pow(1 - torch.exp(-1 * omiga_h), 4)
            iou = iou - 0.5 * (distance_cost + shape_cost)
        loss = 1.0 - iou

        if self.reduction == 'sum':
            loss = loss.sum()
        elif self.reduction == 'mean':
            loss = loss.mean()

        return loss

3.def pairwise_bbox_iou(box1, box2, box_format='xywh'): 

python">def pairwise_bbox_iou(box1, box2, box_format='xywh'):
    """Calculate iou.
    This code is based on https://github.com/Megvii-BaseDetection/YOLOX/blob/main/yolox/utils/boxes.py
    """
    # lt (left top) :计算交集的左上角坐标,使用 torch.max 取两个边界框左上角的最大值。
    # rb (right bottom) :计算交集的右下角坐标,使用 torch.min 取两个边界框右下角的最小值。
    if box_format == 'xyxy':
        lt = torch.max(box1[:, None, :2], box2[:, :2])
        rb = torch.min(box1[:, None, 2:], box2[:, 2:])
        area_1 = torch.prod(box1[:, 2:] - box1[:, :2], 1)
        area_2 = torch.prod(box2[:, 2:] - box2[:, :2], 1)

    elif box_format == 'xywh':
        lt = torch.max(
            (box1[:, None, :2] - box1[:, None, 2:] / 2),
            (box2[:, :2] - box2[:, 2:] / 2),
        )
        rb = torch.min(
            (box1[:, None, :2] + box1[:, None, 2:] / 2),
            (box2[:, :2] + box2[:, 2:] / 2),
        )

        area_1 = torch.prod(box1[:, 2:], 1)
        area_2 = torch.prod(box2[:, 2:], 1)
    valid = (lt < rb).type(lt.type()).prod(dim=2)
    inter = torch.prod(rb - lt, 2) * valid
    # area_1[:, None] 是第一个边界框的面积,通过在 area_1 前面增加一个 None 维度,使其从一维数组变成二维数组,以便于进行广播(broadcasting)操作。
    return inter / (area_1[:, None] + area_2 - inter)

# 在表达式 inter / (area_1[:, None] + area_2 - inter) 中, [:, None] 操作的意义是增加一个额外的维度,以便于进行广播(broadcasting)操作。这是一种常见的操作,用于使具有不同形状的数组能够进行数学运算。
# 具体来说 :
# 1. area_1[:, None] :
# area_1 是一个一维数组,包含了每个边界框的面积。
# [:, None] 操作在 area_1 的第二个维度(索引为 1 的维度)增加了一个新的轴,将其从形状 (n,) 变为 (n, 1) ,其中 n 是边界框的数量。
# 2. 广播机制 :
# 在 PyTorch 中,广播机制允许形状不同的数组进行数学运算。当一个数组的形状是 (n, 1) ,另一个数组的形状是 (m,) 时,它们可以进行运算,因为 PyTorch 会自动将形状为 (m,) 的数组扩展到 (m, 1) ,然后沿着新的维度进行广播,使其形状变为 (n, m) 。
# 3. 应用在本例中:
# area_1[:, None] 使得 area_1 从 (n,) 变为 (n, 1) 。
# area_2 也是一个一维数组,形状为 (m,) 。
# 当执行 area_1[:, None] + area_2 时, area_2 被广播到 (n, m) ,其中 n 是 area_1 的长度, m 是 area_2 的长度。
# 这样,每个 area_1 中的元素都会与 area_2 中的每个元素相加,得到一个形状为 (n, m) 的结果。
# 4. 计算并集面积:
# 通过这种方式, area_1[:, None] + area_2 - inter 计算的是每个 area_1 中的边界框面积与每个 area_2 中的边界框面积之和,再减去它们之间的交集面积 inter ,得到并集面积。
# 总结来说, [:, None] 操作是为了使一维数组能够与另一个一维数组进行广播运算,从而在计算 IoU 时能够处理多个边界框的面积。这种操作在处理多维数组和批量操作时非常有用。


http://www.niftyadmin.cn/n/5744194.html

相关文章

【热门主题】000027 React:前端框架的强大力量

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

◇【论文_20160610】Generative Adversarial Imitation Learning 【附录 A】

文章目录 A 证明Section 3 的证明引理 3.1 证明命题 3.2 的证明 A.2 Section 5 的证明命题 A.1推论 A.1.1引理 A.1 因果熵的策略梯度公式 A 证明 Section 3 的证明 引理 3.1 证明 Proof of Lemma 3.1. 首先&#xff0c;我们证明 H ˉ \bar H Hˉ 是严格凹的。 令 ρ \rho ρ…

阿里云多端低代码开发平台魔笔使用测评

文章目录 前言一、魔笔是什么&#xff1f;二、测评1.基本组件布局2.前端逻辑3.事件绑定 总结 前言 最近对于低代码平台挺感兴趣的&#xff0c;了解到很多云服务&#xff0c;国内有很多的这种平台&#xff0c;最近阿里云推出了他们的多端低代码开发平台魔笔&#xff0c;目前还在…

qt QTextCursor详解

1、概述 QTextCursor是Qt框架中用于在QTextDocument或QTextEdit中编辑和导航文本的类。它提供了对文本选择和编辑操作的低级控制&#xff0c;允许插入、删除、修改文本以及改变文本的格式。QTextCursor可以看作是一个在文本中移动的插入点或选择区域&#xff0c;通过它可以执行…

uniapp实现H5和微信小程序获取当前位置(腾讯地图)

之前的一个老项目&#xff0c;使用 uniapp 的 uni.getLocation 发现H5端定位不准确&#xff0c;比如余杭区会定位到临平区&#xff0c;根据官方文档初步判断是项目的uniapp的版本太低。 我选择的方式不是区更新uniapp的版本&#xff0c;是直接使用高德地图的api获取定位。 1.首…

【深度学习】论文笔记:空间变换网络(Spatial Transformer Networks)

博主简介&#xff1a;努力学习的22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a; Yaoyao2024往期回顾&#xff1a; 【机器学习】有监督学习由浅入深讲解分类算法Fisher算法讲解每日一言&#x1f33c;: 今天不想跑&#xff0c;所以才去跑&#xff0c;这才是长…

RK3568 关于python依赖Miniconda3虚拟环境自启动

有关如何安装Miniconda3可以查看博客:RK3568 安装Miniconda3_miniconda3 aarch64 linux-CSDN博客 然后目前有个需求是需要开机自启动python脚本,但是需要依赖于虚拟环境,也就是说一起来就要打开虚拟环境并运行python脚本,一旦没有虚拟环境,python脚本就无法运行 解决办法…

Go语言的常用内置函数

文章目录 一、Strings包字符串处理包定义Strings包的基本用法Strconv包中常用函数 二、Time包三、Math包math包概述使用math包 四、随机数包&#xff08;rand&#xff09; 一、Strings包 字符串处理包定义 Strings包简介&#xff1a; 一般编程语言包含的字符串处理库功能区别…