try: f = [] # image files # 创建一个空列表f,用于存储找到的图像文件路径
# 下面的循环处理img_path,这可以是单个路径或路径列表 for p in img_path ifisinstance(img_path, list) else [img_path]: p = Path(p) # os-agnostic # 使用Path处理路径,以便跨操作系统兼容
if p.is_dir(): # dir # 如果p是一个目录 # 使用glob模块搜索所有子目录中的所有文件,并将它们添加到列表f中 f += glob.glob(str(p / '**' / '*.*'), recursive=True) # F = list(p.rglob('*.*')) # pathlib # 这是另一种使用pathlib模块的方法
elif p.is_file(): # file # 如果p是一个文件 # 打开文件,并读取其中的内容,这些内容通常是图像文件的路径 withopen(p) as t: t = t.read().strip().splitlines() parent = str(p.parent) + os.sep # 对于每个文件路径,转换为绝对路径,并添加到列表f中 f += [x.replace('./', parent) if x.startswith('./') else x for x in t]
else: # 如果路径既不是文件也不是目录,则抛出一个异常 raise FileNotFoundError(f'{self.prefix}{p} does not exist')
# 对找到的文件进行筛选,只保留图像格式的文件,这里IMG_FORMATS是一个包含图像文件扩展名的列表 im_files = sorted(x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in IMG_FORMATS)
# 确保找到了图像文件,否则抛出异常 assert im_files, f'{self.prefix}No images found in {img_path}'
except Exception as e: # 如果在处理过程中发生任何异常,抛出一个异常,指明无法从给定路径加载数据 raise FileNotFoundError(f'{self.prefix}Error loading data from {img_path}\n{HELP_URL}') from e
defupdate_labels(self, include_class: Optional[list]): """Update labels to include only these classes (optional)."""# 定义方法update_labels,用于更新标签以仅包含指定的类别
for i, x in pbar: # 遍历每个图像的缓存结果 if cache == 'disk': # 如果缓存到磁盘 b += self.npy_files[i].stat().st_size # 更新已缓存图像的总字节数 else: # 'ram' 如果缓存到内存 self.ims[i], self.im_hw0[i], self.im_hw[i] = x # 更新缓存的图像及其原始和调整后的尺寸 b += self.ims[i].nbytes # 更新已缓存图像的总字节数
pbar.close() # 关闭进度条 defcache_images_to_disk(self, i): """Saves an image as an *.npy file for faster loading."""# 定义方法cache_images_to_disk,用于将图像保存为.npy文件以加快加载速度
f = self.npy_files[i] # 获取索引为i的.npy文件的路径
ifnot f.exists(): # 检查该.npy文件是否已存在 # 如果不存在,则读取对应的图像文件,并将其保存为.npy格式 np.save(f.as_posix(), cv2.imread(self.im_files[i]), allow_pickle=False) defcheck_cache_ram(self, safety_margin=0.5): """Check image caching requirements vs available memory."""# 定义方法check_cache_ram,用于检查缓存图像所需的内存
b, gb = 0, 1 << 30# bytes of cached images, bytes per gigabytes # 初始化用于计算缓存图像大小的变量,gb是1GB的字节数
n = min(self.ni, 30) # extrapolate from 30 random images # 选择30个随机图像(或者整个数据集的图像数量,如果它小于30)来估计所需内存
for _ inrange(n): im = cv2.imread(random.choice(self.im_files)) # sample image # 随机选择一个图像进行读取
ratio = self.imgsz / max(im.shape[0], im.shape[1]) # max(h, w) # ratio # 计算图像缩放比例(如果有缩放的话)
b += im.nbytes * ratio ** 2# 计算这个图像缩放后占用的字节数,并累加到总量
mem_required = b * self.ni / n * (1 + safety_margin) # GB required to cache dataset into RAM # 计算整个数据集缓存到RAM所需的内存大小,考虑安全余量
mem = psutil.virtual_memory() # 获取系统的虚拟内存信息
cache = mem_required < mem.available # to cache or not to cache, that is the question # 判断是否有足够的内存进行缓存
这段代码的目的是在使用YOLO(You Only Look Once)检测算法时,设置边界框的形状为矩形。YOLO是一种流行的对象检测算法,它在处理图像时需要考虑边界框的形状。这段代码通过调整图像的排序和批处理形状来优化YOLO的性能。通过分析数据集中图像的宽高比,来优化批处理中的图像形状。这样的优化可以帮助YOLO算法更有效地处理不同形状和尺寸的图像,提高对象检测的准确性和效率。
defset_rectangle(self): """Sets the shape of bounding boxes for YOLO detections as rectangles."""# 定义set_rectangle方法,用于设置YOLO检测的边界框形状为矩形 bi = np.floor(np.arange(self.ni) / self.batch_size).astype(int) # batch index # 计算每张图像所属的批次索引 nb = bi[-1] + 1# number of batches # 计算总批次数量 s = np.array([x.pop('shape') for x in self.labels]) # hw # 提取每个标签中的图像尺寸(高度和宽度) ar = s[:, 0] / s[:, 1] # aspect ratio # 计算每个图像的宽高比 irect = ar.argsort() # 获取宽高比排序的索引 self.im_files = [self.im_files[i] for i in irect] self.labels = [self.labels[i] for i in irect] # 根据宽高比重新排序图像文件和标签 ar = ar[irect] # 更新宽高比数组为排序后的顺序 # Set training image shapes shapes = [[1, 1]] * nb # 初始化每个批次的图像形状数组 for i inrange(nb): ari = ar[bi == i] # 获取每个批次的宽高比 mini, maxi = ari.min(), ari.max() # 计算每个批次的最小和最大宽高比 # 设置每个批次的图像形状 if maxi < 1: shapes[i] = [maxi, 1] elif mini > 1: shapes[i] = [1, 1 / mini] # 计算每个批次的实际图像形状,考虑图像大小和步长 self.batch_shapes = np.ceil(np.array(shapes) * self.imgsz / self.stride + self.pad).astype(int) * self.stride self.batch = bi # batch index of image # 设置每张图像的批次索引
def__len__(self): """Returns the length of the labels list for the dataset.""" returnlen(self.labels)
defupdate_labels_info(self, label): """Custom your label format here.""" return label
defbuild_transforms(self, hyp=None): """ Users can customize augmentations here. Example: ```python if self.augment: # Training transforms return Compose([]) else: # Val transforms return Compose([])
"""
raise NotImplementedError
def get_labels(self):
"""
Users can customize their own format here.
Note:
Ensure output is a dictionary with the following keys: