当前位置: 首页 > news >正文

YOLOv12_ultralytics-8.3.145_2025_5_27部分代码阅读笔记-instance.py

instance.py

ultralytics\utils\instance.py

目录

instance.py

1.所需的库和模块

2.def _ntuple(n): 

3.class Bboxes: 

4.class Instances: 


1.所需的库和模块

# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/licensefrom collections import abc
from itertools import repeat
from numbers import Number
from typing import Listimport numpy as npfrom .ops import ltwh2xywh, ltwh2xyxy, resample_segments, xywh2ltwh, xywh2xyxy, xyxy2ltwh, xyxy2xywh

2.def _ntuple(n): 

# 这段代码定义了一个名为 _ntuple 的函数,其目的是创建一个能够将输入值转换为长度为 n 的元组的函数,如果输入值是单个值,则会将其重复 n 次来生成元组。
# 这行代码定义了一个函数 _ntuple ,它接收一个参数 1.n ,这个参数将决定生成的元组的长度。
def _ntuple(n):# 创建一个函数,通过重复单例值将输入转换为 n 元组。"""Create a function that converts input to n-tuple by repeating singleton values."""# 在 _ntuple 函数内部,定义了一个嵌套函数 parse ,这个函数将用于处理具体的输入值 1.x 。def parse(x):# 通过重复单例值 n 次来解析输入以返回 n 元组。"""Parse input to return n-tuple by repeating singleton values n times."""# 这行代码是 parse 函数的核心逻辑:# isinstance(x, abc.Iterable) :检查输入值 x 是否是可迭代对象(如列表、元组、字符串等)。如果是可迭代对象,则直接返回 x 。# tuple(repeat(x, n)) :如果 x 不是可迭代对象,则使用 repeat 函数将 x 重复 n 次,并将其转换为元组返回。return x if isinstance(x, abc.Iterable) else tuple(repeat(x, n))# 返回嵌套函数 parse ,这样 _ntuple 函数的作用就是生成并返回这个 parse 函数。return parse
# 这段代码通过定义 _ntuple 函数,实现了一个功能:根据传入的参数 n ,生成一个能够将输入值转换为长度为 n 的元组的函数。如果输入值是单个值,则会重复该值 n 次;如果输入值是可迭代对象,则直接返回该可迭代对象。这种设计模式在处理输入参数时非常有用,尤其是在需要统一处理不同类型的输入值时。# 通过调用 _ntuple(2) ,创建了一个函数 to_2tuple ,该函数可以将输入值转换为长度为2的元组。如果输入是一个单个值,它会将该值重复两次;如果输入是一个可迭代对象,它会直接返回该对象。
to_2tuple = _ntuple(2)
# 通过调用 _ntuple(4) ,创建了一个函数 to_4tuple ,该函数可以将输入值转换为长度为4的元组。如果输入是一个单个值,它会将该值重复四次;如果输入是一个可迭代对象,它会直接返回该对象。
to_4tuple = _ntuple(4)# `xyxy` means left top and right bottom
# `xywh` means center x, center y and width, height(YOLO format)
# `ltwh` means left top and width, height(COCO format)
# 这里定义了一个列表 _formats ,包含了三种常见的边界框格式:
# xyxy :表示边界框的左上角坐标 (x1, y1) 和右下角坐标 (x2, y2) 。
# xywh :表示边界框的中心点坐标 (x_center, y_center) 以及宽度 width 和高度 height (YOLO格式)。
# ltwh :表示边界框的左上角坐标 (x1, y1) 以及宽度 width 和高度 height (COCO格式)。
_formats = ["xyxy", "xywh", "ltwh"]# 定义了模块的导出列表 __all__ ,指定了当使用 from module_name import * 时,哪些类或函数会被导入。 在这里,模块导出了两个名称: Bboxes 和 Instances 。这表明模块中可能定义了这两个类或函数,供其他代码使用。
__all__ = ("Bboxes", "Instances")  # tuple or list

3.class Bboxes: 

# 这段代码定义了一个名为 Bboxes 的类,用于处理多种格式的边界框(bounding boxes),并提供了格式转换、面积计算、缩放、平移以及多个边界框对象的拼接等功能。
# 这行代码定义了一个名为 Bboxes 的类,用于处理边界框数据。
class Bboxes:# 一个用于处理多种格式边界框的类。# 该类支持各种边界框格式,例如“xyxy”、“xywh”和“ltwh”,并提供格式转换、缩放和面积计算的方法。边界框数据应以 NumPy 数组的形式提供。# 属性:# bboxes (np.ndarray):存储在形状为 (N, 4) 的二维 NumPy 数组中的边界框。# format (str):边界框的格式(“xyxy”、“xywh”或“ltwh”)。# 方法:# convert:将边界框格式从一种类型转换为另一种类型。# areas:计算边界框的面积。# mul:将边界框坐标乘以比例因子。# add:将偏移量添加到边界框坐标。# concatenate:连接多个 Bboxes 对象。# 注意:# 此类不处理边界框的规范化或非规范化。"""A class for handling bounding boxes in multiple formats.The class supports various bounding box formats like 'xyxy', 'xywh', and 'ltwh' and provides methods for formatconversion, scaling, and area calculation. Bounding box data should be provided as numpy arrays.Attributes:bboxes (np.ndarray): The bounding boxes stored in a 2D numpy array with shape (N, 4).format (str): The format of the bounding boxes ('xyxy', 'xywh', or 'ltwh').Methods:convert: Convert bounding box format from one type to another.areas: Calculate the area of bounding boxes.mul: Multiply bounding box coordinates by scale factor(s).add: Add offset to bounding box coordinates.concatenate: Concatenate multiple Bboxes objects.Examples:Create bounding boxes in YOLO format>>> bboxes = Bboxes(np.array([[100, 50, 150, 100]]), format="xywh")>>> bboxes.convert("xyxy")>>> print(bboxes.areas())Notes:This class does not handle normalization or denormalization of bounding boxes."""# 这段代码是 Bboxes 类的初始化方法 __init__ 的定义,用于创建 Bboxes 对象时初始化边界框数据和格式。# 定义了 Bboxes 类的初始化方法 __init__ 。 该方法接收两个参数:# 1.bboxes :边界框数据,应为一个 NumPy 数组,形状为 (N, 4) 或 (4,) 。# 2.format :边界框的格式,默认值为 "xyxy" ,表示边界框的左上角和右下角坐标。# 方法的返回类型为 None ,表示初始化方法不返回任何值。def __init__(self, bboxes, format="xyxy") -> None:# 使用指定格式的边界框数据初始化 Bboxes 类。# 参数:# bboxes (np.ndarray):形状为 (N, 4) 或 (4,) 的边界框数组。# format (str):边界框的格式,可以是“xyxy”、“xywh”或“ltwh”之一。"""Initialize the Bboxes class with bounding box data in a specified format.Args:bboxes (np.ndarray): Array of bounding boxes with shape (N, 4) or (4,).format (str): Format of the bounding boxes, one of 'xyxy', 'xywh', or 'ltwh'."""# 使用 assert 语句检查传入的 format 是否在 _formats 列表中。# _formats 是一个包含支持的边界框格式的列表,定义为 ["xyxy", "xywh", "ltwh"] 。# 如果 format 不在 _formats 中,抛出异常,提示无效的边界框格式,并说明支持的格式。assert format in _formats, f"Invalid bounding box format: {format}, format must be one of {_formats}"    # 边界框格式无效:{format},格式必须是 {_formats} 之一。# 检查 bboxes 的维度 ndim 。 如果 bboxes 是一维数组(形状为 (4,) ),则通过在前面添加一个新维度将其转换为二维数组(形状为 (1, 4) )。 这样可以确保边界框数据始终是一个二维数组,方便后续处理。bboxes = bboxes[None, :] if bboxes.ndim == 1 else bboxes# 再次检查 bboxes 是否是二维数组。 如果不是二维数组,抛出异常,确保边界框数据的维度正确。assert bboxes.ndim == 2# 检查 bboxes 的第二维大小是否为 4。 每个边界框有 4 个坐标值,因此第二维大小必须为 4。 如果不满足条件,抛出异常。assert bboxes.shape[1] == 4# 将传入的边界框数据 bboxes 赋值给类的 bboxes 属性,以便后续方法可以访问和操作这些数据。self.bboxes = bboxes# 将传入的边界框格式 format 赋值给类的 format 属性,记录当前边界框的格式。self.format = format# 这段代码的作用是初始化 Bboxes 类的实例,确保传入的边界框数据和格式符合要求,并将其存储为类的属性。主要步骤包括: 验证传入的边界框格式是否有效。 确保边界框数据是一个二维数组,形状为 (N, 4) 。 将边界框数据和格式存储为类的属性,以便后续方法可以使用。通过这些步骤, Bboxes 类的实例在创建时就能保证数据的正确性和一致性,为后续的操作(如格式转换、面积计算等)打下基础。# 这段代码定义了 Bboxes 类中的 convert 方法,用于将边界框的格式从当前格式转换为目标格式。# 定义了 convert 方法,该方法接收一个参数 1.format ,表示目标边界框格式。def convert(self, format):# 将边界框格式从一种类型转换为另一种类型。"""Convert bounding box format from one type to another.Args:format (str): Target format for conversion, one of 'xyxy', 'xywh', or 'ltwh'."""# 使用 assert 语句检查目标格式 format 是否在 _formats 列表中。 _formats 是一个包含支持的边界框格式的列表,定义为 ["xyxy", "xywh", "ltwh"] 。 如果目标格式不在 _formats 中,抛出异常,提示无效的边界框格式,并说明支持的格式。assert format in _formats, f"Invalid bounding box format: {format}, format must be one of {_formats}"    # 边界框格式无效:{format},格式必须是 {_formats} 之一。# 如果当前格式 self.format 与目标格式 format 相同,则无需进行转换,直接返回。 这一步避免了不必要的计算。if self.format == format:return# 如果当前格式为 "xyxy" ,则根据目标格式选择相应的转换函数: 如果目标格式为 "xywh" ,则选择 xyxy2xywh 函数。 如果目标格式为 "ltwh" ,则选择 xyxy2ltwh 函数。elif self.format == "xyxy":func = xyxy2xywh if format == "xywh" else xyxy2ltwh# 如果当前格式为 "xywh" ,则根据目标格式选择相应的转换函数: 如果目标格式为 "xyxy" ,则选择 xywh2xyxy 函数。 如果目标格式为 "ltwh" ,则选择 xywh2ltwh 函数。elif self.format == "xywh":func = xywh2xyxy if format == "xyxy" else xywh2ltwh# 如果当前格式为 "ltwh" ,则根据目标格式选择相应的转换函数: 如果目标格式为 "xyxy" ,则选择 ltwh2xyxy 函数。 如果目标格式为 "xywh" ,则选择 ltwh2xywh 函数。else:func = ltwh2xyxy if format == "xyxy" else ltwh2xywh# 调用选定的转换函数 func ,将当前边界框数据 self.bboxes 转换为目标格式。 转换后的边界框数据重新赋值给 self.bboxes 。self.bboxes = func(self.bboxes)# 更新类的 format 属性为目标格式,以反映边界框数据的新格式。self.format = format# 这段代码的作用是将边界框的格式从当前格式转换为目标格式。主要步骤包括: 验证目标格式是否有效。 检查当前格式是否与目标格式相同,如果相同则无需转换。 根据当前格式和目标格式选择相应的转换函数。 调用转换函数,将边界框数据转换为目标格式。 更新类的 format 属性为目标格式。通过这些步骤, convert 方法能够灵活地在不同边界框格式之间进行转换,确保边界框数据在不同格式之间的一致性和正确性。# 这段代码定义了 Bboxes 类中的 areas 方法,用于计算边界框的面积。# 定义了 areas 方法,该方法不接收额外的参数,直接计算当前 Bboxes 对象中所有边界框的面积。def areas(self):# 计算边界框的面积。"""Calculate the area of bounding boxes."""# 根据边界框的格式计算面积:# 如果当前格式为 "xyxy" ,则面积计算公式为 (x2 - x1) * (y2 - y1) ,其中 x1 、 y1 是左上角坐标, x2 、 y2 是右下角坐标。# 如果当前格式为 "xywh" 或 "ltwh" ,则面积计算公式为 width * height ,其中 width 是宽度, height 是高度。# 使用三元运算符( if-else 表达式)根据当前格式选择相应的面积计算公式。# 计算得到的面积值以 NumPy 数组的形式返回,每个元素对应一个边界框的面积。return ((self.bboxes[:, 2] - self.bboxes[:, 0]) * (self.bboxes[:, 3] - self.bboxes[:, 1])  # format xyxyif self.format == "xyxy"else self.bboxes[:, 3] * self.bboxes[:, 2]  # format xywh or ltwh)# 这段代码的作用是计算 Bboxes 对象中所有边界框的面积。主要步骤包括: 根据当前边界框的格式选择相应的面积计算公式。 使用 NumPy 数组的切片和运算计算每个边界框的面积。 将计算得到的面积值以 NumPy 数组的形式返回。通过这些步骤, areas 方法能够高效地计算边界框的面积,为后续的处理(如目标检测、图像分割等)提供有用的信息。# 这段代码定义了 Bboxes 类中的 mul 方法,用于将边界框的坐标乘以指定的缩放因子。# 定义了 mul 方法,该方法接收一个参数 1.scale ,表示缩放因子。def mul(self, scale):# 将边界框坐标乘以比例因子。"""Multiply bounding box coordinates by scale factor(s).Args:scale (int | tuple | list): Scale factor(s) for four coordinates. If int, the same scale is applied toall coordinates."""# 检查 scale 是否是一个数字( Number 类型,包括整数和浮点数)。# 如果是数字,则调用 to_4tuple 函数将其转换为一个长度为 4 的元组。 to_4tuple 函数会将单个值重复 4 次,生成一个元组 (scale, scale, scale, scale) 。# 这样可以确保 scale 是一个包含 4 个缩放因子的元组或列表。if isinstance(scale, Number):scale = to_4tuple(scale)# 检查 scale 是否是元组或列表。 如果不是元组或列表,抛出异常,确保 scale 的类型正确。assert isinstance(scale, (tuple, list))# 检查 scale 的长度是否为 4。 如果长度不是 4,抛出异常,确保 scale 包含 4 个缩放因子。assert len(scale) == 4# 将边界框的每个坐标分别乘以相应的缩放因子:# self.bboxes[:, 0] :边界框的第 1 个坐标(例如, x1 或 x_center )乘以 scale[0] 。# self.bboxes[:, 1] :边界框的第 2 个坐标(例如, y1 或 y_center )乘以 scale[1] 。# self.bboxes[:, 2] :边界框的第 3 个坐标(例如, x2 或 width )乘以 scale[2] 。# self.bboxes[:, 3] :边界框的第 4 个坐标(例如, y2 或 height )乘以 scale[3] 。# 这些操作直接修改了 self.bboxes 数组中的值。self.bboxes[:, 0] *= scale[0]self.bboxes[:, 1] *= scale[1]self.bboxes[:, 2] *= scale[2]self.bboxes[:, 3] *= scale[3]# 这段代码的作用是将边界框的坐标乘以指定的缩放因子。主要步骤包括: 检查 scale 是否是一个数字,如果是,则将其转换为长度为 4 的元组。 确保 scale 是一个元组或列表,并且长度为 4。 将边界框的每个坐标分别乘以相应的缩放因子,直接修改 self.bboxes 数组中的值。通过这些步骤, mul 方法能够灵活地对边界框的坐标进行缩放,适用于图像缩放、坐标变换等场景。# 这段代码定义了 Bboxes 类中的 add 方法,用于将偏移量加到边界框的坐标上。# 定义了 add 方法,该方法接收一个参数 1.offset ,表示要加到边界框坐标上的偏移量。def add(self, offset):# 为边界框坐标添加偏移量。"""Add offset to bounding box coordinates.Args:offset (int | tuple | list): Offset(s) for four coordinates. If int, the same offset is applied toall coordinates."""# 检查 offset 是否是一个数字( Number 类型,包括整数和浮点数)。# 如果是数字,则调用 to_4tuple 函数将其转换为一个长度为 4 的元组。 to_4tuple 函数会将单个值重复 4 次,生成一个元组 (offset, offset, offset, offset) 。# 这样可以确保 offset 是一个包含 4 个偏移量的元组或列表。if isinstance(offset, Number):offset = to_4tuple(offset)# 检查 offset 是否是元组或列表。 如果不是元组或列表,抛出异常,确保 offset 的类型正确。assert isinstance(offset, (tuple, list))# 检查 offset    的长度是否为 4。 如果长度不是 4,抛出异常,确保 offset 包含 4 个偏移量。assert len(offset) == 4# 将边界框的每个坐标分别加上相应的偏移量:# self.bboxes[:, 0] :边界框的第 1 个坐标(例如, x1 或 x_center )加上 offset[0] 。# self.bboxes[:, 1] :边界框的第 2 个坐标(例如, y1 或 y_center )加上 offset[1] 。# self.bboxes[:, 2] :边界框的第 3 个坐标(例如, x2 或 width )加上 offset[2] 。# self.bboxes[:, 3] :边界框的第 4 个坐标(例如, y2 或 height )加上 offset[3] 。# 些操作直接修改了 self.bboxes 数组中的值。self.bboxes[:, 0] += offset[0]self.bboxes[:, 1] += offset[1]self.bboxes[:, 2] += offset[2]self.bboxes[:, 3] += offset[3]# 这段代码的作用是将偏移量加到边界框的坐标上。主要步骤包括: 检查 offset 是否是一个数字,如果是,则将其转换为长度为 4 的元组。 确保 offset 是一个元组或列表,并且长度为 4。 将边界框的每个坐标分别加上相应的偏移量,直接修改 self.bboxes 数组中的值。通过这些步骤, add 方法能够灵活地对边界框的坐标进行平移,适用于图像平移、坐标调整等场景。# 这段代码定义了 Bboxes 类中的 __len__ 方法,用于返回边界框的数量。# 定义了 __len__ 方法。这是一个特殊方法,用于实现 Python 的内置 len() 函数对 Bboxes 类的支持。 当调用 len(bboxes_instance) 时,Python 会自动调用这个方法。def __len__(self):# 返回边界框的数量。"""Return the number of bounding boxes."""# 返回 self.bboxes 的长度,即边界框的数量。 self.bboxes 是一个二维 NumPy 数组,其形状为 (N, 4) ,其中 N 是边界框的数量。 使用 len(self.bboxes) 可以直接获取边界框的数量。return len(self.bboxes)# 这段代码的作用是实现 Bboxes 类对 len() 函数的支持,返回边界框的数量。主要步骤包括: 定义 __len__ 方法。 返回 self.bboxes 的长度,即边界框的数量。通过这个方法,用户可以方便地使用 len() 函数来获取 Bboxes 对象中边界框的数量,这使得 Bboxes 类的行为更加符合 Python 的内置数据结构,提高了代码的可读性和易用性。# 这段代码定义了 Bboxes 类中的 concatenate 类方法,用于将多个 Bboxes 对象拼接成一个新的 Bboxes 对象。# 使用 @classmethod 装饰器定义了一个类方法 concatenate 。@classmethod# 该方法接收两个参数:# 1.boxes_list :一个包含多个 Bboxes 对象的列表或元组。# 2.axis :拼接的轴,默认值为 0,表示沿第一个轴(即边界框的数量轴)进行拼接。# 方法返回一个新的 Bboxes 对象。def concatenate(cls, boxes_list: List["Bboxes"], axis=0) -> "Bboxes":# 将 Bboxes 对象列表连接成单个 Bboxes 对象。# 备注:# 输入应为 Bboxes 对象的列表或元组。"""Concatenate a list of Bboxes objects into a single Bboxes object.Args:boxes_list (List[Bboxes]): A list of Bboxes objects to concatenate.axis (int, optional): The axis along which to concatenate the bounding boxes.Returns:(Bboxes): A new Bboxes object containing the concatenated bounding boxes.Notes:The input should be a list or tuple of Bboxes objects."""# 检查 boxes_list 是否是一个列表或元组。 如果不是列表或元组,抛出异常,确保输入的类型正确。assert isinstance(boxes_list, (list, tuple))# 如果 boxes_list 为空(即没有提供任何 Bboxes 对象),则返回一个空的 Bboxes 对象。 使用 np.empty(0) 创建一个空的 NumPy 数组,并将其传递给 Bboxes 类的构造函数。if not boxes_list:return cls(np.empty(0))# 检查 boxes_list 中的每个元素是否都是 Bboxes 类的实例。 如果有任何一个元素不是 Bboxes 对象,抛出异常,确保输入的每个对象都是有效的 Bboxes 实例。assert all(isinstance(box, Bboxes) for box in boxes_list)# 如果 boxes_list 中只有一个 Bboxes 对象,则直接返回该对象。 这一步避免了不必要的拼接操作,提高了效率。if len(boxes_list) == 1:return boxes_list[0]# 如果 boxes_list 中有多个 Bboxes 对象,则提取每个对象的 bboxes 属性(即边界框数据)。# 使用 np.concatenate 函数将这些边界框数据沿指定的轴 axis 拼接成一个新的 NumPy 数组。# 使用拼接后的 NumPy 数组创建一个新的 Bboxes 对象并返回。return cls(np.concatenate([b.bboxes for b in boxes_list], axis=axis))# 这段代码的作用是将多个 Bboxes 对象拼接成一个新的 Bboxes 对象。主要步骤包括: 检查输入的 boxes_list 是否是一个列表或元组。 如果 boxes_list 为空,则返回一个空的 Bboxes 对象。 检查 boxes_list 中的每个元素是否都是 Bboxes 对象。 如果 boxes_list 中只有一个 Bboxes 对象,则直接返回该对象。 如果 boxes_list 中有多个 Bboxes 对象,则提取每个对象的边界框数据,沿指定轴拼接成一个新的 NumPy 数组,并用该数组创建一个新的 Bboxes 对象。通过这些步骤, concatenate 方法能够灵活地将多个边界框对象合并为一个,适用于需要处理多个边界框集合的场景。# 这段代码定义了 Bboxes 类中的 __getitem__ 方法,用于实现对边界框对象的索引操作。# 定义了 __getitem__ 方法,该方法接收一个参数 1.index ,表示索引或切片操作。 方法返回一个新的 Bboxes 对象,包含根据索引或切片操作选择的边界框。def __getitem__(self, index) -> "Bboxes":# 使用索引检索特定边界框或一组边界框。# 注意事项:# 使用布尔索引时,请确保提供与边界框数量长度相同的布尔数组。"""Retrieve a specific bounding box or a set of bounding boxes using indexing.Args:index (int | slice | np.ndarray): The index, slice, or boolean array to select the desired bounding boxes.Returns:(Bboxes): A new Bboxes object containing the selected bounding boxes.Notes:When using boolean indexing, make sure to provide a boolean array with the same length as the number ofbounding boxes."""# 检查 index 是否是一个整数。# 如果是整数,则表示选择单个边界框。# 使用 self.bboxes[index] 获取单个边界框数据,该数据是一个一维数组。# 使用 .reshape(1, -1) 将一维数组转换为二维数组(形状为 (1, 4) ),以确保返回的边界框数据符合 Bboxes 类的要求。# 使用转换后的边界框数据创建一个新的 Bboxes 对象并返回。if isinstance(index, int):return Bboxes(self.bboxes[index].reshape(1, -1))# 如果 index 不是整数,则表示使用切片或其他索引方式(如布尔索引)。 使用 self.bboxes[index] 获取根据索引选择的边界框数据,存储在变量 b 中。b = self.bboxes[index]# 检查 b 是否是一个二维数组。 如果 b 不是二维数组,抛出异常,提示索引操作失败。 这一步确保返回的边界框数据是一个二维数组,符合 Bboxes 类的要求。assert b.ndim == 2, f"Indexing on Bboxes with {index} failed to return a matrix!"    # 使用 {index} 对 Bbox 进行索引无法返回矩阵!# 使用选择的边界框数据 b 创建一个新的 Bboxes 对象并返回。return Bboxes(b)# 这段代码的作用是实现对 Bboxes 对象的索引操作,返回一个新的 Bboxes 对象,包含根据索引或切片操作选择的边界框。主要步骤包括: 检查索引是否是整数,如果是,则选择单个边界框并将其转换为二维数组。 如果索引不是整数,则使用索引操作获取边界框数据。 确保返回的边界框数据是一个二维数组。 使用返回的边界框数据创建一个新的 Bboxes 对象。通过这些步骤, __getitem__ 方法使得 Bboxes 类的对象可以像普通列表或数组一样进行索引和切片操作,提高了类的灵活性和易用性。
# Bboxes 类是一个用于处理和操作多种格式边界框数据的工具类。它支持常见的边界框格式(如 "xyxy" 、 "xywh" 和 "ltwh" ),并提供了丰富的功能,包括格式转换、面积计算、坐标缩放和平移,以及多个边界框对象的拼接。通过灵活的索引和切片操作,用户可以方便地选择和操作边界框子集。该类的设计注重易用性和效率,适用于计算机视觉任务中的目标检测和边界框处理。

4.class Instances: 

# 这段代码定义了一个名为 Instances 的类,用于封装图像中检测到的对象的边界框(bounding boxes)、分割掩码(segments)和关键点(keypoints)。它提供了统一的接口来处理不同类型的目标标注,并支持多种操作,如缩放、归一化、裁剪和格式转换。
# 定义了一个名为 Instances 的类,该类用于管理图像中检测到的对象的各种标注信息。
class Instances:# 用于存储图像中检测到的对象的边界框、线段和关键点的容器。# 此类提供统一的接口,用于处理不同类型的对象标注,包括边界框、分割蒙版和关键点。它支持缩放、归一化、裁剪和格式转换等各种操作。# 属性:# _bboxes (Bboxes):用于处理边界框操作的内部对象。# keypoints (np.ndarray):形状为 (N, 17, 3) 的关键点,格式为 (x, y, visible)。# normalized (bool):指示边界框坐标是否已归一化的标志。# segments (np.ndarray):重采样后形状为 (N, M, 2) 的线段数组。# 方法:# convert_bbox:转换边界框格式。# scale:按指定因子缩放坐标。# denormalize:将归一化坐标转换为绝对坐标。# normalize:将绝对坐标转换为归一化坐标。# add_padding:添加填充坐标。# flipud:垂直翻转坐标。# fliplr:水平翻转坐标。# clip:裁剪坐标使其保持在图像边界内。# remove_zero_area_boxes:移除面积为零的框。# update:更新实例变量。# concatenate:连接多个实例对象。"""Container for bounding boxes, segments, and keypoints of detected objects in an image.This class provides a unified interface for handling different types of object annotations including boundingboxes, segmentation masks, and keypoints. It supports various operations like scaling, normalization, clipping,and format conversion.Attributes:_bboxes (Bboxes): Internal object for handling bounding box operations.keypoints (np.ndarray): Keypoints with shape (N, 17, 3) in format (x, y, visible).normalized (bool): Flag indicating whether the bounding box coordinates are normalized.segments (np.ndarray): Segments array with shape (N, M, 2) after resampling.Methods:convert_bbox: Convert bounding box format.scale: Scale coordinates by given factors.denormalize: Convert normalized coordinates to absolute coordinates.normalize: Convert absolute coordinates to normalized coordinates.add_padding: Add padding to coordinates.flipud: Flip coordinates vertically.fliplr: Flip coordinates horizontally.clip: Clip coordinates to stay within image boundaries.remove_zero_area_boxes: Remove boxes with zero area.update: Update instance variables.concatenate: Concatenate multiple Instances objects.Examples:Create instances with bounding boxes and segments>>> instances = Instances(...     bboxes=np.array([[10, 10, 30, 30], [20, 20, 40, 40]]),...     segments=[np.array([[5, 5], [10, 10]]), np.array([[15, 15], [20, 20]])],...     keypoints=np.array([[[5, 5, 1], [10, 10, 1]], [[15, 15, 1], [20, 20, 1]]]),... )"""# 这段代码定义了 Instances 类的初始化方法 __init__ ,用于创建类的实例并初始化其属性。# 定义了 Instances 类的初始化方法 __init__ 。 接受以下参数:# 1.bboxes :边界框数组,形状为 (N, 4) ,表示有 N 个边界框。# 2.segments :分割掩码,可以是列表或 NumPy 数组,形状为 (N, M, 2) ,表示有 N 个分割掩码,每个掩码有 M 个点。# 3.keypoints :关键点数组,形状为 (N, K, 3) ,表示有 N 个关键点集,每个关键点集有 K 个关键点,每个关键点有 (x, y, visible) 三个值。# 4.bbox_format :边界框的格式,默认为 "xywh" ,表示边界框的格式为 (x, y, width, height) 。# 5.normalized :布尔值,表示边界框坐标是否已经归一化,默认为 True 。# 返回值: None ,表示这是一个初始化方法,不返回任何值。def __init__(self, bboxes, segments=None, keypoints=None, bbox_format="xywh", normalized=True) -> None:# 使用边界框、线段和关键点初始化实例对象。# 参数:# bboxes (np.ndarray):形状为 (N, 4) 的边界框。# segments (List | np.ndarray,可选):分割蒙版。# keypoints (np.ndarray,可选):形状为 (N, 17, 3) 的关键点,格式为 (x, y, visible)。# bbox_format (str):bboxes 的格式。# normalized (bool):坐标是否已归一化。"""Initialize the Instances object with bounding boxes, segments, and keypoints.Args:bboxes (np.ndarray): Bounding boxes with shape (N, 4).segments (List | np.ndarray, optional): Segmentation masks.keypoints (np.ndarray, optional): Keypoints with shape (N, 17, 3) in format (x, y, visible).bbox_format (str): Format of bboxes.normalized (bool): Whether the coordinates are normalized."""# 创建一个 Bboxes 对象,用于管理边界框。 将边界框数据 bboxes 和边界框格式 bbox_format 传递给 Bboxes 类的构造函数。 将创建的 Bboxes 对象存储在 self._bboxes 属性中。self._bboxes = Bboxes(bboxes=bboxes, format=bbox_format)# 将传入的关键点数组 keypoints 直接存储在 self.keypoints 属性中。self.keypoints = keypoints# 将传入的归一化标志 normalized 存储在 self.normalized 属性中,表示边界框坐标是否已经归一化。self.normalized = normalized# 将传入的分割掩码 segments 直接存储在 self.segments 属性中。self.segments = segments# 这段代码的作用是初始化 Instances 类的实例,设置其边界框、分割掩码、关键点、边界框格式和归一化标志等属性。通过这种方式, Instances 类可以方便地管理图像中检测到的对象的各种标注信息,并为后续的操作(如缩放、归一化、裁剪等)提供基础。# 这段代码定义了 Instances 类中的一个方法 convert_bbox ,用于将边界框的格式从当前格式转换为目标格式。# 定义了一个名为 convert_bbox 的方法,该方法属于 Instances 类。 方法接受一个参数 1.format ,表示目标边界框格式。# 参数 format 的值可以是 'xyxy' 、 'xywh' 或 'ltwh' 等,具体取决于边界框的表示方式:# 'xyxy' :表示边界框的左上角和右下角坐标 (x1, y1, x2, y2) 。# 'xywh' :表示边界框的中心点坐标 (x, y) 和宽度、高度 (w, h) 。# 'ltwh' :表示边界框的左上角坐标 (x, y) 和宽度、高度 (w, h) 。def convert_bbox(self, format):# 转换边界框格式。"""Convert bounding box format.Args:format (str): Target format for conversion, one of 'xyxy', 'xywh', or 'ltwh'."""# 调用了 _bboxes 对象的 convert 方法,并将目标格式 format 传递给该方法。# _bboxes 是一个 Bboxes 类的实例,负责管理边界框的操作。# _bboxes.convert(format=format) 的作用是将 _bboxes 中存储的边界框从当前格式转换为目标格式。self._bboxes.convert(format=format)# 这段代码的作用是将 Instances 类中存储的边界框从当前格式转换为目标格式。通过调用 _bboxes 对象的 convert 方法,可以方便地实现边界框格式的转换。这在处理不同格式的边界框数据时非常有用,例如在目标检测任务中,不同的模型或数据集可能使用不同的边界框格式。通过 convert_bbox 方法,可以统一边界框的格式,便于后续处理和操作。# 这段代码定义了 Instances 类中的一个属性 bbox_areas ,用于计算并返回边界框的面积。# 使用 Python 的装饰器 @property ,将 bbox_areas 方法定义为一个属性。这意味着可以通过 instances.bbox_areas 的方式直接访问这个方法的返回值,而不需要显式调用方法(即不需要加括号)。@property# 定义了一个名为 bbox_areas 的方法,该方法属于 Instances 类。 这个方法没有接受额外的参数,只使用类的内部属性。def bbox_areas(self):# 计算边界框的面积。"""Calculate the area of bounding boxes."""# 调用了 _bboxes 对象的 areas 方法,并返回其结果。 _bboxes 是一个 Bboxes 类的实例,负责管理边界框的操作。 self._bboxes.areas() 的作用是计算 _bboxes 中所有边界框的面积,并返回一个包含这些面积的数组。return self._bboxes.areas()# 这段代码的作用是提供一个便捷的属性接口,用于计算并返回 Instances 类中存储的边界框的面积。通过定义 bbox_areas 为一个属性,用户可以直接访问边界框的面积,而无需显式调用方法。这使得代码更加简洁和易用。# 这段代码定义了 Instances 类中的一个方法 scale ,用于按给定的因子缩放边界框、分割掩码和关键点的坐标。# 定义了一个名为 scale 的方法,属于 Instances 类。 方法接受三个参数:# 1.scale_w :宽度方向的缩放因子。# 2.scale_h :高度方向的缩放因子。# 3.bbox_only :布尔值,默认为 False ,表示是否只缩放边界框,而不缩放分割掩码和关键点。def scale(self, scale_w, scale_h, bbox_only=False):# 按指定比例缩放坐标。"""Scale coordinates by given factors.Args:scale_w (float): Scale factor for width.scale_h (float): Scale factor for height.bbox_only (bool, optional): Whether to scale only bounding boxes."""# 调用 _bboxes 对象的 mul 方法,将边界框的坐标按指定的宽度和高度因子进行缩放。 _bboxes.mul(scale=(scale_w, scale_h, scale_w, scale_h)) 的作用是将边界框的左上角和右下角坐标分别按 scale_w 和 scale_h 缩放。self._bboxes.mul(scale=(scale_w, scale_h, scale_w, scale_h))# 如果 bbox_only 为 True ,则直接返回,不执行后续的分割掩码和关键点的缩放操作。if bbox_only:return# 如果 bbox_only 为 False ,则继续缩放分割掩码的坐标。# self.segments[..., 0] 表示分割掩码中所有点的 x 坐标, self.segments[..., 1] 表示分割掩码中所有点的 y 坐标。# 将分割掩码的 x 坐标按 scale_w 缩放,y 坐标按 scale_h 缩放。self.segments[..., 0] *= scale_wself.segments[..., 1] *= scale_h# 如果存在关键点( self.keypoints 不为 None ),则继续缩放关键点的坐标。# self.keypoints[..., 0] 表示关键点中所有点的 x 坐标, self.keypoints[..., 1] 表示关键点中所有点的 y 坐标。# 将关键点的 x 坐标按 scale_w 缩放,y 坐标按 scale_h 缩放。if self.keypoints is not None:self.keypoints[..., 0] *= scale_wself.keypoints[..., 1] *= scale_h# 这段代码的作用是按给定的因子缩放 Instances 类中存储的边界框、分割掩码和关键点的坐标。通过 scale 方法,可以灵活地控制是否只缩放边界框,或者同时缩放分割掩码和关键点。这在处理图像尺寸变化(如缩放、裁剪等)时非常有用,可以确保所有相关的标注信息同步更新。# 这段代码定义了 Instances 类中的一个方法 denormalize ,用于将归一化的坐标转换为绝对坐标。# 定义了一个名为 denormalize 的方法,属于 Instances 类。 方法接受两个参数:# 1.w :图像的宽度。# 2.h :图像的高度。def denormalize(self, w, h):# 将规范化坐标转换为绝对坐标。"""Convert normalized coordinates to absolute coordinates.Args:w (int): Image width.h (int): Image height."""# 检查 self.normalized 标志是否为 True 。 如果 self.normalized 为 False ,表示当前坐标已经是绝对坐标,无需进行去归一化操作,直接返回。if not self.normalized:return# 调用 _bboxes 对象的 mul 方法,将边界框的坐标按图像的宽度和高度转换为绝对坐标。 _bboxes.mul(scale=(w, h, w, h)) 的作用是将边界框的左上角和右下角坐标分别按 w 和 h 缩放。self._bboxes.mul(scale=(w, h, w, h))# 将分割掩码的 x 坐标按图像宽度 w 缩放,y 坐标按图像高度 h 缩放。 self.segments[..., 0] 表示分割掩码中所有点的 x 坐标, self.segments[..., 1] 表示分割掩码中所有点的 y 坐标。self.segments[..., 0] *= wself.segments[..., 1] *= h# 如果存在关键点( self.keypoints 不为 None ),则将关键点的 x 坐标按图像宽度 w 缩放,y 坐标按图像高度 h 缩放。 self.keypoints[..., 0] 表示关键点中所有点的 x 坐标, self.keypoints[..., 1] 表示关键点中所有点的 y 坐标。if self.keypoints is not None:self.keypoints[..., 0] *= wself.keypoints[..., 1] *= h# 将 self.normalized 标志设置为 False ,表示坐标已经转换为绝对坐标。self.normalized = False# 这段代码的作用是将 Instances 类中存储的归一化坐标转换为绝对坐标。通过调用 denormalize 方法并传入图像的宽度和高度,可以将边界框、分割掩码和关键点的坐标从归一化形式转换为绝对形式。这在处理图像数据时非常有用,特别是在需要将归一化的标注信息转换为实际像素坐标时。# 这段代码定义了 Instances 类中的一个方法 normalize ,用于将绝对坐标转换为归一化坐标。# 定义了一个名为 normalize 的方法,属于 Instances 类。 方法接受两个参数:# 1.w :图像的宽度。# 2.h :图像的高度。def normalize(self, w, h):# 将绝对坐标转换为规范化坐标。"""Convert absolute coordinates to normalized coordinates.Args:w (int): Image width.h (int): Image height."""# 检查 self.normalized 标志是否为 True 。 如果 self.normalized 为 True ,表示当前坐标已经是归一化坐标,无需进行归一化操作,直接返回。if self.normalized:return# 调用 _bboxes 对象的 mul 方法,将边界框的坐标按图像的宽度和高度的倒数进行缩放,从而将边界框的绝对坐标转换为归一化坐标。# _bboxes.mul(scale=(1 / w, 1 / h, 1 / w, 1 / h)) 的作用是将边界框的左上角和右下角坐标分别按 1 / w 和 1 / h 缩放。self._bboxes.mul(scale=(1 / w, 1 / h, 1 / w, 1 / h))# 将分割掩码的 x 坐标按图像宽度 w 的倒数进行缩放,y 坐标按图像高度 h 的倒数进行缩放。 self.segments[..., 0] 表示分割掩码中所有点的 x 坐标, self.segments[..., 1] 表示分割掩码中所有点的 y 坐标。self.segments[..., 0] /= wself.segments[..., 1] /= h# 如果存在关键点( self.keypoints 不为 None ),则将关键点的 x 坐标按图像宽度 w 的倒数进行缩放,y 坐标按图像高度 h 的倒数进行缩放。# self.keypoints[..., 0] 表示关键点中所有点的 x 坐标, self.keypoints[..., 1] 表示关键点中所有点的 y 坐标。if self.keypoints is not None:self.keypoints[..., 0] /= wself.keypoints[..., 1] /= h# 将 self.normalized 标志设置为 True ,表示坐标已经转换为归一化坐标。self.normalized = True# 这段代码的作用是将 Instances 类中存储的绝对坐标转换为归一化坐标。通过调用 normalize 方法并传入图像的宽度和高度,可以将边界框、分割掩码和关键点的坐标从绝对形式转换为归一化形式。这在处理图像数据时非常有用,特别是在需要将标注信息标准化以便于模型训练或跨图像比较时。# 这段代码定义了 Instances 类中的一个方法 add_padding ,用于向边界框、分割掩码和关键点的坐标添加填充(padding)。# 定义了一个名为 add_padding 的方法,属于 Instances 类。 方法接受两个参数:# 1.padw :宽度方向的填充量。# 2.padh :高度方向的填充量。def add_padding(self, padw, padh):# 为坐标添加内边距。"""Add padding to coordinates.Args:padw (int): Padding width.padh (int): Padding height."""# 使用 assert 语句检查 self.normalized 标志是否为 False 。 如果 self.normalized 为 True ,表示当前坐标是归一化的,而添加填充操作只能在绝对坐标上进行,因此抛出错误信息 "you should add padding with absolute coordinates." 。assert not self.normalized, "you should add padding with absolute coordinates."    # 您应该添加具有绝对坐标的填充。# 调用 _bboxes 对象的 add 方法,将边界框的坐标按指定的填充量进行偏移。 _bboxes.add(offset=(padw, padh, padw, padh)) 的作用是将边界框的左上角和右下角坐标分别按 padw 和 padh 进行偏移。self._bboxes.add(offset=(padw, padh, padw, padh))# 将分割掩码的 x 坐标按宽度方向的填充量 padw 进行偏移,y 坐标按高度方向的填充量 padh 进行偏移。 self.segments[..., 0] 表示分割掩码中所有点的 x 坐标, self.segments[..., 1] 表示分割掩码中所有点的 y 坐标。self.segments[..., 0] += padwself.segments[..., 1] += padh# 如果存在关键点( self.keypoints 不为 None ),则将关键点的 x 坐标按宽度方向的填充量 padw 进行偏移,y 坐标按高度方向的填充量 padh 进行偏移。# self.keypoints[..., 0] 表示关键点中所有点的 x 坐标, self.keypoints[..., 1] 表示关键点中所有点的 y 坐标。if self.keypoints is not None:self.keypoints[..., 0] += padwself.keypoints[..., 1] += padh# 这段代码的作用是向 Instances 类中存储的边界框、分割掩码和关键点的坐标添加填充。通过调用 add_padding 方法并传入宽度和高度方向的填充量,可以将所有相关的标注信息同步更新。这在处理图像数据时非常有用,特别是在需要对图像进行填充操作(如在图像边缘添加边界)时。# 这段代码定义了 Instances 类中的一个方法 __getitem__ ,用于通过索引访问特定的实例或一组实例。# 定义了一个名为 __getitem__ 的方法,属于 Instances 类。 方法接受一个参数 1.index ,表示要访问的实例的索引。 index 可以是整数、切片(slice)或布尔数组。 返回值是一个新的 Instances 对象,包含选定的边界框、分割掩码和关键点。def __getitem__(self, index) -> "Instances":# 使用索引检索特定实例或一组实例。# 注意事项:# 使用布尔索引时,请确保提供与实例数量长度相同的布尔数组。"""Retrieve a specific instance or a set of instances using indexing.Args:index (int | slice | np.ndarray): The index, slice, or boolean array to select the desired instances.Returns:(Instances): A new Instances object containing the selected boxes, segments, and keypoints if present.Notes:When using boolean indexing, make sure to provide a boolean array with the same length as the number ofinstances."""# 根据索引 index 获取分割掩码。 如果 self.segments 是一个空列表或数组,则直接返回 self.segments ,否则按索引提取对应的分割掩码。segments = self.segments[index] if len(self.segments) else self.segments# 根据索引 index 获取关键点。 如果 self.keypoints 为 None ,则返回 None ,否则按索引提取对应的关键点。keypoints = self.keypoints[index] if self.keypoints is not None else None# 根据索引 index 获取边界框。bboxes = self.bboxes[index]# 获取当前边界框的格式。bbox_format = self._bboxes.format# 使用提取的边界框、分割掩码、关键点、边界框格式和归一化标志创建一个新的 Instances 对象,并返回该对象。return Instances(bboxes=bboxes,segments=segments,keypoints=keypoints,bbox_format=bbox_format,normalized=self.normalized,)# 这段代码的作用是通过索引访问 Instances 类中的特定实例或一组实例。通过 __getitem__ 方法,可以方便地提取和操作子集。这在处理批量数据或筛选特定实例时非常有用。# 这段代码定义了 Instances 类中的一个方法 flipud ,用于将边界框、分割掩码和关键点的坐标进行垂直翻转(即上下翻转)。# 定义了一个名为 flipud 的方法,属于 Instances 类。 方法接受一个参数 1.h ,表示图像的高度。def flipud(self, h):# 垂直翻转坐标。"""Flip coordinates vertically.Args:h (int): Image height."""# 检查边界框的格式是否为 "xyxy" 。# 如果是 "xyxy" 格式,边界框的坐标表示为 (x1, y1, x2, y2) ,其中 (x1, y1) 是左上角坐标, (x2, y2) 是右下角坐标。# 为了实现垂直翻转,需要将 y1 和 y2 互换,并分别从图像高度 h 中减去它们的值: y1 变为 h - y2 , y2 变为 h - y1 。if self._bboxes.format == "xyxy":y1 = self.bboxes[:, 1].copy()y2 = self.bboxes[:, 3].copy()self.bboxes[:, 1] = h - y2self.bboxes[:, 3] = h - y1# 如果边界框的格式不是 "xyxy" (例如 "xywh" 或 "ltwh" ),则直接将边界框的 y 坐标从图像高度 h 中减去,实现垂直翻转。else:self.bboxes[:, 1] = h - self.bboxes[:, 1]# 将分割掩码的 y 坐标从图像高度 h 中减去,实现垂直翻转。 self.segments[..., 1] 表示分割掩码中所有点的 y 坐标。self.segments[..., 1] = h - self.segments[..., 1]# 如果存在关键点( self.keypoints 不为 None ),则将关键点的 y 坐标从图像高度 h 中减去,实现垂直翻转。 self.keypoints[..., 1] 表示关键点中所有点的 y 坐标。if self.keypoints is not None:self.keypoints[..., 1] = h - self.keypoints[..., 1]# 这段代码的作用是将 Instances 类中存储的边界框、分割掩码和关键点的坐标进行垂直翻转。通过调用 flipud 方法并传入图像的高度,可以将所有相关的标注信息同步更新。这在处理图像数据时非常有用,特别是在需要对图像进行垂直翻转操作时。# 这段代码定义了 Instances 类中的一个方法 fliplr ,用于将边界框、分割掩码和关键点的坐标进行水平翻转(即左右翻转)。# 定义了一个名为 fliplr 的方法,属于 Instances 类。 方法接受一个参数 1.w ,表示图像的宽度。def fliplr(self, w):# 水平翻转坐标。"""Flip coordinates horizontally.Args:w (int): Image width."""# 检查边界框的格式是否为 "xyxy" 。# 如果是 "xyxy" 格式,边界框的坐标表示为 (x1, y1, x2, y2) ,其中 (x1, y1) 是左上角坐标, (x2, y2) 是右下角坐标。# 为了实现水平翻转,需要将 x1 和 x2 互换,并分别从图像宽度 w 中减去它们的值: x1 变为 w - x2 , x2 变为 w - x1 。if self._bboxes.format == "xyxy":x1 = self.bboxes[:, 0].copy()x2 = self.bboxes[:, 2].copy()self.bboxes[:, 0] = w - x2self.bboxes[:, 2] = w - x1# 如果边界框的格式不是 "xyxy" (例如 "xywh" 或 "ltwh" ),则直接将边界框的 x 坐标从图像宽度 w 中减去,实现水平翻转。else:self.bboxes[:, 0] = w - self.bboxes[:, 0]# 将分割掩码的 x 坐标从图像宽度 w 中减去,实现水平翻转。 self.segments[..., 0] 表示分割掩码中所有点的 x 坐标。self.segments[..., 0] = w - self.segments[..., 0]# 如果存在关键点( self.keypoints 不为 None ),则将关键点的 x 坐标从图像宽度 w 中减去,实现水平翻转。 self.keypoints[..., 0] 表示关键点中所有点的 x 坐标。if self.keypoints is not None:self.keypoints[..., 0] = w - self.keypoints[..., 0]# 这段代码的作用是将 Instances 类中存储的边界框、分割掩码和关键点的坐标进行水平翻转。通过调用 fliplr 方法并传入图像的宽度,可以将所有相关的标注信息同步更新。这在处理图像数据时非常有用,特别是在需要对图像进行水平翻转操作时。# 这段代码定义了 Instances 类中的一个方法 clip ,用于将边界框、分割掩码和关键点的坐标裁剪到图像边界内。# 定义了一个名为 clip 的方法,属于 Instances 类。 方法接受两个参数:# 1.w :图像的宽度。# 2.h :图像的高度。def clip(self, w, h):# 裁剪坐标以保持在图像边界内。"""Clip coordinates to stay within image boundaries.Args:w (int): Image width.h (int): Image height."""# 保存当前边界框的格式,以便在裁剪完成后恢复原始格式。ori_format = self._bboxes.format# 将边界框的格式转换为 "xyxy" ,因为裁剪操作需要基于 (x1, y1, x2, y2) 格式的边界框进行。self.convert_bbox(format="xyxy")# 将边界框的 x 坐标( x1 和 x2 )裁剪到 [0, w] 范围内。 将边界框的 y 坐标( y1 和 y2 )裁剪到 [0, h] 范围内。 使用 NumPy 的 clip 方法,确保坐标不会超出图像边界。self.bboxes[:, [0, 2]] = self.bboxes[:, [0, 2]].clip(0, w)self.bboxes[:, [1, 3]] = self.bboxes[:, [1, 3]].clip(0, h)# 如果原始边界框格式不是 "xyxy" ,则将边界框格式恢复为原始格式。if ori_format != "xyxy":self.convert_bbox(format=ori_format)# 将分割掩码的 x 坐标裁剪到 [0, w] 范围内。# 将分割掩码的 y 坐标裁剪到 [0, h] 范围内。self.segments[..., 0] = self.segments[..., 0].clip(0, w)self.segments[..., 1] = self.segments[..., 1].clip(0, h)# 如果存在关键点( self.keypoints 不为 None ),则将超出图像边界的点的可见性设置为 0。# self.keypoints[..., 2] 表示关键点的可见性标志。# 使用布尔索引,将超出 [0, w] 或 [0, h] 范围的关键点的可见性标志设置为 0。if self.keypoints is not None:# Set out of bounds visibility to zeroself.keypoints[..., 2][(self.keypoints[..., 0] < 0)| (self.keypoints[..., 0] > w)| (self.keypoints[..., 1] < 0)| (self.keypoints[..., 1] > h)] = 0.0# 这段代码的作用是将 Instances 类中存储的边界框、分割掩码和关键点的坐标裁剪到图像边界内。通过调用 clip 方法并传入图像的宽度和高度,可以确保所有相关的标注信息不会超出图像的边界。这在处理图像数据时非常有用,特别是在需要对图像进行裁剪或调整大小时。# 这段代码定义了 Instances 类中的一个方法 remove_zero_area_boxes ,用于移除面积为零的边界框,并同步更新相关的分割掩码和关键点。# 定义了一个名为 remove_zero_area_boxes 的方法,属于 Instances 类。 方法没有接受额外的参数。def remove_zero_area_boxes(self):# 移除面积为零的框,即裁剪后某些框的宽度或高度可能为零。"""Remove zero-area boxes, i.e. after clipping some boxes may have zero width or height.Returns:(np.ndarray): Boolean array indicating which boxes were kept."""# 计算每个边界框的面积,并生成一个布尔数组 good ,表示哪些边界框的面积大于零。 self.bbox_areas 是一个属性,返回边界框的面积数组。 good 是一个布尔数组,其中 True 表示边界框的面积大于零, False 表示边界框的面积为零。good = self.bbox_areas > 0# 检查是否所有边界框的面积都大于零。 如果不是(即存在面积为零的边界框),则需要进行过滤。if not all(good):# 使用布尔索引 good 过滤掉面积为零的边界框。 self._bboxes[good] 会返回一个新的 Bboxes 对象,只包含面积大于零的边界框。self._bboxes = self._bboxes[good]# 如果存在分割掩码( self.segments 不为空),则使用相同的布尔索引 good 过滤掉对应的分割掩码。 self.segments[good] 会返回一个新的分割掩码数组,只包含面积大于零的边界框对应的分割掩码。if len(self.segments):self.segments = self.segments[good]# 如果存在关键点( self.keypoints 不为 None ),则使用相同的布尔索引 good 过滤掉对应的关键点。 self.keypoints[good] 会返回一个新的关键点数组,只包含面积大于零的边界框对应的关键点。if self.keypoints is not None:self.keypoints = self.keypoints[good]# 返回布尔数组 good ,表示哪些边界框被保留(面积大于零)。return good# 这段代码的作用是移除 Instances 类中面积为零的边界框,并同步更新相关的分割掩码和关键点。通过调用 remove_zero_area_boxes 方法,可以确保所有相关的标注信息中不包含无效的边界框。这在处理图像数据时非常有用,特别是在需要清理数据集中的无效标注时。# 这段代码定义了 Instances 类中的一个方法 update ,用于更新实例中的边界框、分割掩码和关键点。# 定义了一个名为 update 的方法,属于 Instances 类。 方法接受三个参数:# 1.bboxes :新的边界框数组,形状为 (N, 4) 。# 2.segments :新的分割掩码数组,形状为 (N, M, 2) ,其中 M 是每个分割掩码的点数。# 3.keypoints :新的关键点数组,形状为 (N, K, 3) ,其中 K 是每个实例的关键点数。def update(self, bboxes, segments=None, keypoints=None):# 更新实例变量。"""Update instance variables.Args:bboxes (np.ndarray): New bounding boxes.segments (np.ndarray, optional): New segments.keypoints (np.ndarray, optional): New keypoints."""# 使用新的边界框数据 bboxes 创建一个新的 Bboxes 对象,并将其存储在 self._bboxes 属性中。 保持边界框的格式不变,使用当前 _bboxes 对象的格式 self._bboxes.format 。self._bboxes = Bboxes(bboxes, format=self._bboxes.format)# 如果提供了新的分割掩码 segments ,则更新 self.segments 属性。if segments is not None:self.segments = segments# 如果提供了新的关键点 keypoints ,则更新 self.keypoints 属性。if keypoints is not None:self.keypoints = keypoints# 这段代码的作用是更新 Instances 类中的边界框、分割掩码和关键点。通过调用 update 方法并传入新的边界框、分割掩码和关键点,可以方便地替换现有的标注信息。这在处理图像数据时非常有用,特别是在需要更新或修正标注信息时。# 这段代码定义了 Instances 类中的一个方法 __len__ ,用于返回实例中边界框的数量。# 定义了一个名为 __len__ 的方法,属于 Instances 类。 __len__ 是一个特殊方法,用于实现 len() 函数对类实例的支持。 方法没有接受额外的参数。def __len__(self):# 返回实例的数量。"""Return the number of instances."""# 返回 self.bboxes 的长度,即边界框的数量。 self.bboxes 是一个 NumPy 数组,表示所有边界框的坐标。 len(self.bboxes) 返回边界框数组的长度,即边界框的数量。return len(self.bboxes)# 这段代码的作用是实现 len() 函数对 Instances 类实例的支持,返回实例中边界框的数量。通过定义 __len__ 方法,可以方便地使用 len() 函数获取边界框的数量。这在处理图像数据时非常有用,特别是在需要统计或遍历边界框时。# 这段代码定义了 Instances 类中的一个类方法 concatenate ,用于将多个 Instances 对象合并成一个 Instances 对象。@classmethod# 定义了一个名为 concatenate 的类方法,属于 Instances 类。 方法接受两个参数:# 1.instances_list :一个包含多个 Instances 对象的列表。# 2.axis :沿哪个轴进行拼接,默认为 0 ,表示按行拼接。def concatenate(cls, instances_list: List["Instances"], axis=0) -> "Instances":# 将实例对象列表连接为单个实例对象。# 注意:# 列表中的“实例”对象应具有相同的属性,例如边界框的格式、是否存在关键点以及坐标是否已归一化。"""Concatenate a list of Instances objects into a single Instances object.Args:instances_list (List[Instances]): A list of Instances objects to concatenate.axis (int, optional): The axis along which the arrays will be concatenated.Returns:(Instances): A new Instances object containing the concatenated bounding boxes, segments, and keypointsif present.Notes:The `Instances` objects in the list should have the same properties, such as the format of the boundingboxes, whether keypoints are present, and if the coordinates are normalized."""# 断言 instances_list 是一个列表或元组。assert isinstance(instances_list, (list, tuple))# 如果 instances_list 为空,返回一个包含空边界框的 Instances 对象。if not instances_list:return cls(np.empty(0))# 断言 instances_list 中的所有元素都是 Instances 类的实例。assert all(isinstance(instance, Instances) for instance in instances_list)# 如果 instances_list 只有一个元素,直接返回该元素。if len(instances_list) == 1:return instances_list[0]# 检查第一个 Instances 对象是否包含关键点。use_keypoint = instances_list[0].keypoints is not None# 获取第一个 Instances 对象的边界框格式。bbox_format = instances_list[0]._bboxes.format# 获取第一个 Instances 对象的归一化标志。normalized = instances_list[0].normalized# 沿指定轴拼接所有 Instances 对象的边界框。cat_boxes = np.concatenate([ins.bboxes for ins in instances_list], axis=axis)# 获取每个 Instances 对象的分割掩码的长度。seg_len = [b.segments.shape[1] for b in instances_list]# 检查分割掩码的长度是否一致。 seg_len 是一个列表,包含每个 Instances 对象的分割掩码长度。 frozenset(seg_len) 将 seg_len 转换为一个不可变集合,自动去除重复值。 如果集合的长度大于 1,说明分割掩码的长度不一致,需要进行重采样。if len(frozenset(seg_len)) > 1:  # resample segments if there's different length# 找到所有分割掩码中的最大长度 max_len ,这将作为统一的长度标准。max_len = max(seg_len)# 遍历 instances_list 中的每个 Instances 对象 b 。# 对于每个 Instances 对象:# 如果该对象有分割掩码( len(b.segments) > 0 ),则调用 resample_segments 函数,将分割掩码重采样到统一的长度 max_len 。# 如果该对象没有分割掩码,则生成一个形状为 (0, max_len, 2) 的空数组,表示没有分割掩码。# 将所有处理后的分割掩码沿指定轴 axis 拼接成一个大的数组 cat_segments 。cat_segments = np.concatenate([resample_segments(list(b.segments), max_len)if len(b.segments)else np.zeros((0, max_len, 2), dtype=np.float32)  # re-generating empty segmentsfor b in instances_list],axis=axis,)# 如果分割掩码的长度一致,直接沿指定轴拼接。else:cat_segments = np.concatenate([b.segments for b in instances_list], axis=axis)# 如果存在关键点,沿指定轴拼接所有 Instances 对象的关键点。cat_keypoints = np.concatenate([b.keypoints for b in instances_list], axis=axis) if use_keypoint else None# 使用拼接后的边界框、分割掩码和关键点创建一个新的 Instances 对象,并返回该对象。return cls(cat_boxes, cat_segments, cat_keypoints, bbox_format, normalized)# 这段代码的作用是将多个 Instances 对象合并成一个 Instances 对象。通过调用 concatenate 方法并传入一个包含多个 Instances 对象的列表,可以方便地将它们合并。这在处理批量数据时非常有用,特别是在需要将多个图像的标注信息合并时。# 这段代码定义了 Instances 类中的一个属性 bboxes ,用于访问边界框数据。# 使用 @property 装饰器定义了一个名为 bboxes 的属性。@property# 这使得 bboxes 可以像访问普通属性一样被调用,而不需要显式调用方法(即不需要加括号)。def bboxes(self):# 返回边界框。"""Return bounding boxes."""# 返回 _bboxes 对象中的 bboxes 属性。 _bboxes 是一个 Bboxes 类的实例,负责管理边界框的操作。 _bboxes.bboxes 是一个 NumPy 数组,存储了所有边界框的坐标。return self._bboxes.bboxes# 这段代码的作用是提供一个便捷的属性接口,用于访问 Instances 类中存储的边界框数据。通过定义 bboxes 为一个属性,用户可以直接访问边界框数据,而无需显式调用方法。这使得代码更加简洁和易用。
# Instances 类是一个用于封装图像中检测到的对象的边界框(bounding boxes)、分割掩码(segments)和关键点(keypoints)的容器类。它提供了统一的接口来处理不同类型的目标标注信息,并支持多种操作,如边界框格式转换、坐标缩放、归一化、裁剪、翻转以及无效边界框的移除等。通过 Instances 类,可以方便地管理和操作图像中的标注信息,适用于目标检测、实例分割和关键点检测等多种计算机视觉任务。

 

http://www.dtcms.com/a/263333.html

相关文章:

  • [15-2] 读写内部FLASH读取芯片ID 江协科技学习笔记(20个知识点)
  • MySQL DATETIME 类型时间精度陷阱:一次由毫秒引发的数据“消失”之谜
  • 【Actix Web】Rust Web开发实战:Actix Web框架全面指南(2025企业级应用版)
  • java初学习(-2025.6.30小总结)
  • TCP 三次握手协商 MSS 前,如何确定 MSS 值
  • SQL规范
  • 【软考高项论文】论信息系统项目的范围管理
  • 剑指offer51_数组中数值和下标相等的元素
  • 机器人仿真(1)Ubuntu24.04下CLion的ROS2开发环境配置
  • [ C++ ] | unordered_map 底层实现原理
  • Linux-进程概念(1)
  • 亚马逊,塔吉特采购,测评防砍单封号的养号下单黄金法则
  • 华为云Flexus+DeepSeek征文 | Word办公软件接入华为云ModelArts Studio大模型,实现AI智能办公
  • 【C++指南】C++ list容器完全解读(三):list迭代器的实现与优化
  • Deploy StarRocks with Docker
  • ubuntu源码安装python3.13遇到Could not build the ssl module!解决方法
  • Deepoc 大模型在无人机行业应用效果的方法
  • Python函数参数实例练习--输出信息
  • 抗量子域名系统:全面的系统级研究
  • 前端领域的技术热点与深度解析
  • 对selenium进行浏览器和驱动进行配置Windows | Linux
  • [面试]手写题-Promise.all() Promise.race()
  • 博图SCL编程:结构体(STRUCT)使用详解与实战案例
  • HTML<span>元素详解
  • 安装bcolz包报错Cython.Compiler.Errors.CompileError: bcolz/carray_ext.pyx的解决方法
  • 条件运算符和逗号运算
  • Intel Fortran Compiler (ifx) 详细使用指南:新一代 Fortran 编译器在流体动力学模拟中的应用
  • 51单片机CPU工作原理解析
  • python环境快速搭建
  • 深入比较 Gin 与 Beego:Go Web 框架的两大选择