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

YOLOv11-ultralytics-8.3.67部分代码阅读笔记-VOC.yaml

VOC.yaml

ultralytics\cfg\datasets\VOC.yaml

目录

VOC.yaml

1.YAML文件内容

2.所需的库和模块 

3.def convert_label(path, lb_path, year, image_id): 

4.Download 

5.Convert 


1.YAML文件内容

# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license

# PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC by University of Oxford
# Documentation: # Documentation: https://docs.ultralytics.com/datasets/detect/voc/
# Example usage: yolo train data=VOC.yaml
# parent
# ├── ultralytics
# └── datasets
#     └── VOC  ← downloads here (2.8 GB)

# 示例用法: yolo train data=VOC.yaml


# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]    训练/验证/测试集为 1)目录:path/to/imgs,2)文件:path/to/imgs.txt,或 3)列表:[path/to/imgs1, path/to/imgs2, ..]
path: ../datasets/VOC
train: # train images (relative to 'path')  16551 images    训练图像(相对于“path”) 16551 幅图像。
  - images/train2012
  - images/train2007
  - images/val2012
  - images/val2007
val: # val images (relative to 'path')  4952 images    val 图像(相对于“path”) 4952 幅图像。
  - images/test2007
test: # test images (optional)    测试图像(可选)。
  - images/test2007

# Classes
names:
  0: aeroplane
  1: bicycle
  2: bird
  3: boat
  4: bottle
  5: bus
  6: car
  7: cat
  8: chair
  9: cow
  10: diningtable
  11: dog
  12: horse
  13: motorbike
  14: person
  15: pottedplant
  16: sheep
  17: sofa
  18: train
  19: tvmonitor

# Download script/URL (optional)    下载脚本/URL(可选) ---------------------------------------------------------------------------------------
download: |
  import xml.etree.ElementTree as ET

  from tqdm import tqdm
  from ultralytics.utils.downloads import download
  from pathlib import Path

  def convert_label(path, lb_path, year, image_id):
      def convert_box(size, box):
          dw, dh = 1. / size[0], 1. / size[1]
          x, y, w, h = (box[0] + box[1]) / 2.0 - 1, (box[2] + box[3]) / 2.0 - 1, box[1] - box[0], box[3] - box[2]
          return x * dw, y * dh, w * dw, h * dh

      in_file = open(path / f'VOC{year}/Annotations/{image_id}.xml')
      out_file = open(lb_path, 'w')
      tree = ET.parse(in_file)
      root = tree.getroot()
      size = root.find('size')
      w = int(size.find('width').text)
      h = int(size.find('height').text)

      names = list(yaml['names'].values())  # names list
      for obj in root.iter('object'):
          cls = obj.find('name').text
          if cls in names and int(obj.find('difficult').text) != 1:
              xmlbox = obj.find('bndbox')
              bb = convert_box((w, h), [float(xmlbox.find(x).text) for x in ('xmin', 'xmax', 'ymin', 'ymax')])
              cls_id = names.index(cls)  # class id
              out_file.write(" ".join(str(a) for a in (cls_id, *bb)) + '\n')


  # Download
  dir = Path(yaml['path'])  # dataset root dir
  url = 'https://github.com/ultralytics/assets/releases/download/v0.0.0/'
  urls = [f'{url}VOCtrainval_06-Nov-2007.zip',  # 446MB, 5012 images
          f'{url}VOCtest_06-Nov-2007.zip',  # 438MB, 4953 images
          f'{url}VOCtrainval_11-May-2012.zip']  # 1.95GB, 17126 images
  download(urls, dir=dir / 'images', curl=True, threads=3, exist_ok=True)  # download and unzip over existing paths (required)

  # Convert
  path = dir / 'images/VOCdevkit'
  for year, image_set in ('2012', 'train'), ('2012', 'val'), ('2007', 'train'), ('2007', 'val'), ('2007', 'test'):
      imgs_path = dir / 'images' / f'{image_set}{year}'
      lbs_path = dir / 'labels' / f'{image_set}{year}'
      imgs_path.mkdir(exist_ok=True, parents=True)
      lbs_path.mkdir(exist_ok=True, parents=True)

      with open(path / f'VOC{year}/ImageSets/Main/{image_set}.txt') as f:
          image_ids = f.read().strip().split()
      for id in tqdm(image_ids, desc=f'{image_set}{year}'):
          f = path / f'VOC{year}/JPEGImages/{id}.jpg'  # old img path
          lb_path = (lbs_path / f.name).with_suffix('.txt')  # new label path
          f.rename(imgs_path / f.name)  # move image
          convert_label(path, lb_path, year, id)  # convert labels to YOLO format

2.所需的库和模块 

# Example usage: yolo train data=VOC.yaml

import xml.etree.ElementTree as ET

from tqdm import tqdm
from ultralytics.utils.downloads import download
from pathlib import Path

3.def convert_label(path, lb_path, year, image_id): 

# 这段代码定义了一个名为 convert_label 的函数,用于将 VOC 数据集中的标注文件从 XML 格式转换为 YOLO 格式的标注文件。
# 定义了一个函数 convert_label ,它接受四个参数。
# path :数据集的根目录路径。
# lb_path :转换后的标注文件保存路径。
# year :VOC 数据集的年份(如 2007 或 2012)。
# image_id :图像的 ID,用于定位对应的 XML 标注文件。
def convert_label(path, lb_path, year, image_id):
    # 在函数内部定义了一个嵌套函数 convert_box ,用于将 VOC 标注格式的边界框( xmin , xmax , ymin , ymax )转换为 YOLO 格式( x_center , y_center , width , height )。
    def convert_box(size, box):
        # 计算 宽度和高度的 归一化因子 dw 和 dh ,分别为图像宽度和高度的倒数。
        dw, dh = 1. / size[0], 1. / size[1]
        # 将 VOC 标注格式的边界框转换为 YOLO 格式。
        # x 和 y 分别是边界框中心点的坐标,计算公式为 (xmin + xmax) / 2 和 (ymin + ymax) / 2 ,减去 1 是为了将坐标从 1 开始的索引转换为从 0 开始的索引。
        # w 和 h 分别是边界框的宽度和高度,计算公式为 xmax - xmin 和 ymax - ymin 。
        x, y, w, h = (box[0] + box[1]) / 2.0 - 1, (box[2] + box[3]) / 2.0 - 1, box[1] - box[0], box[3] - box[2]
        # 返回 归一化后的边界框坐标 ,通过乘以 dw 和 dh ,将坐标值归一化到 [0, 1] 范围内。
        return x * dw, y * dh, w * dw, h * dh

    # 打开 VOC 数据集的 XML 标注文件,文件路径通过组合 path 、 year 和 image_id 构造。
    in_file = open(path / f'VOC{year}/Annotations/{image_id}.xml')
    # 打开 目标标注文件路径 lb_path  ,以写入模式打开,用于保存转换后的 YOLO 格式标注。
    out_file = open(lb_path, 'w')

    # ET.parse(source, parser=None)
    # ET.parse() 是 Python 中 xml.etree.ElementTree 模块提供的一个函数,用于解析 XML 文件并将其加载到内存中,以便进行进一步的处理。 ElementTree 是 Python 标准库中用于解析和操作 XML 数据的模块。
    # 参数 :
    # source :类型 :可以是文件名(字符串)、文件对象或类似文件的对象。 说明 :指定要解析的 XML 文件的路径或文件对象。
    # parser (可选) : 类型 : xml.etree.ElementTree.XMLParser 的实例。 说明 :用于解析 XML 的解析器对象。如果不提供,默认使用 XMLParser 。
    # 返回值 :
    # 返回一个 xml.etree.ElementTree.ElementTree 对象,表示解析后的 XML 文档的树形结构。
    # 详细说明 :
    # 解析 XML 文件 :
    # ET.parse(source) 会读取指定的 XML 文件,并将其解析为一个树形结构。
    # 返回的 ElementTree 对象可以用来访问和操作 XML 文档。
    # 获取根节点 :
    # 使用 tree.getroot() 方法可以获取 XML 文档的根节点( <root> )。
    # 遍历 XML 文档 :
    # 使用 findall() 方法可以查找所有匹配的子节点。
    # 使用 find() 方法可以查找第一个匹配的子节点。
    # 使用 .text 属性可以获取节点的文本内容。
    # 使用自定义解析器 :
    # 如果需要自定义解析行为,可以传递一个 XMLParser 实例作为 parser 参数。例如 :
    # parser = ET.XMLParser(encoding='utf-8')
    # tree = ET.parse('example.xml', parser=parser)
    # 总结 : ET.parse() 是一个用于解析 XML 文件的函数,它将 XML 文件加载为一个树形结构,返回一个 ElementTree 对象。通过这个对象,可以方便地访问和操作 XML 文档的各个节点。

    # 使用 xml.etree.ElementTree 模块解析 XML 文件,将其加载到内存中。
    tree = ET.parse(in_file)
    # 获取 XML 文件的根节点,用于 后续遍历 。
    root = tree.getroot()
    # 找到 XML 文件中 <size> 标签,该标签 包含图像的宽度和高度信息 。
    size = root.find('size')
    # 从 <size> 标签中提取图像的 宽度 和 高度 ,并将其转换为整数。
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    # 从 yaml 文件中提取 类别名称列表 。 yaml 文件中包含类别名称的映射, names 是一个列表,存储了 所有可能的类别名称 。
    names = list(yaml['names'].values())  # names list
    # 遍历 XML 文件中所有的 <object> 标签,每个 <object> 标签代表一个 标注对象 。
    for obj in root.iter('object'):
        # 提取当前对象的 类别名称 ,存储在 <name> 标签中。
        cls = obj.find('name').text
        # 检查 类别名称 是否在 names 列表中,并且对象的难度标记( difficult )不为 1。如果类别名称不存在或难度为 1,则跳过该对象。
        if cls in names and int(obj.find('difficult').text) != 1:
            # 提取当前对象的 边界框信息 ,存储在 <bndbox> 标签中。
            xmlbox = obj.find('bndbox')
            # 调用 convert_box 函数,将 VOC 格式的边界框转换为 YOLO 格式。 xmin , xmax , ymin , ymax 是从 <bndbox> 标签中提取的边界框坐标。
            bb = convert_box((w, h), [float(xmlbox.find(x).text) for x in ('xmin', 'xmax', 'ymin', 'ymax')])
            # 获取 当前类别的索引 cls_id ,即类别名称在 names 列表中的位置。
            cls_id = names.index(cls)  # class id
            # 将 类别 ID 和 归一化后的边界框坐标 写入 目标标注文件 ,格式为 class_id x_center y_center width height ,每行代表一个标注对象。
            out_file.write(" ".join(str(a) for a in (cls_id, *bb)) + '\n')
# 这段代码的主要功能是将 VOC 数据集的 XML 标注文件转换为 YOLO 格式的标注文件。它通过解析 XML 文件,提取图像尺寸、对象类别和边界框信息,并将这些信息转换为 YOLO 所需的格式。代码中使用了嵌套函数 convert_box 来完成边界框格式的转换,并通过条件判断过滤掉了难度为 1 的标注对象。最终,转换后的标注信息被写入指定的文件中,以便用于 YOLO 模型的训练或推理。

4.Download 

# 这段代码的作用是下载并解压 VOC 数据集的压缩文件到指定的目录。
# Download
# 从 yaml 配置中获取 path 键对应的值,并将其作为 数据集的根目录路径 。 使用 Path (来自 pathlib 模块)来处理路径, Path 提供了更方便的路径操作方法。
dir = Path(yaml['path'])  # dataset root dir
# 定义一个基础 URL,用于构建完整的下载链接。这里指向的是一个托管在 GitHub 的资源仓库,可能是用于存储数据集文件的仓库。
url = 'https://github.com/ultralytics/assets/releases/download/v0.0.0/'
# 定义一个列表 urls ,包含三个 VOC 数据集的下载链接。
# VOCtrainval_06-Nov-2007.zip :包含 VOC 2007 的训练和验证集,大小约为 446MB,包含 5012 张图像。
# VOCtest_06-Nov-2007.zip :包含 VOC 2007 的测试集,大小约为 438MB,包含 4953 张图像。
# VOCtrainval_11-May-2012.zip :包含 VOC 2012 的训练和验证集,大小约为 1.95GB,包含 17126 张图像。
urls = [f'{url}VOCtrainval_06-Nov-2007.zip',  # 446MB, 5012 images
        f'{url}VOCtest_06-Nov-2007.zip',  # 438MB, 4953 images
        f'{url}VOCtrainval_11-May-2012.zip']  # 1.95GB, 17126 images
# 调用 download 函数,用于 下载和解压数据集文件 。
# urls :包含下载链接的列表。
# dir=dir / 'images' :指定下载和解压的目标目录,路径为 yaml['path'] 下的 images 文件夹。
# curl=True :使用 curl 命令进行下载( curl 是一个常用的命令行工具,用于从网络下载文件)。
# threads=3 :同时使用 3 个线程进行下载,提高下载效率。
# exist_ok=True :如果目标路径已经存在,允许覆盖现有文件。这对于重新下载或更新数据集很有用。
# def download(url, dir=Path.cwd(), unzip=True, delete=False, curl=False, threads=1, retry=3, exist_ok=False): -> 用于从指定的 URL 下载文件,并支持多种功能,包括多线程下载、自动解压、删除源文件、使用 curl 下载等。
download(urls, dir=dir / 'images', curl=True, threads=3, exist_ok=True)  # download and unzip over existing paths (required)
# 这段代码的作用是下载 VOC 数据集的三个压缩文件,并将它们解压到指定的目录。具体步骤如下。从 yaml 配置中获取数据集的根目录路径。构建包含数据集压缩文件下载链接的列表。调用 download 函数,使用 curl 和多线程下载并解压文件到目标目录。如果目标路径已存在,允许覆盖现有文件。

5.Convert 

# 这段代码的作用是将 VOC 数据集的图像和标注文件从原始格式转换为 YOLO 格式,并将它们重新组织到指定的目录结构中。
# Convert
# 定义 path ,指向 VOC 数据集的根目录,通常是 VOCdevkit 文件夹。
path = dir / 'images/VOCdevkit'
# 遍历 VOC 数据集的 不同年份 和 数据集类型 (训练集、验证集、测试集)。这里涉及 VOC 2007 和 VOC 2012 的 train 、 val 和 VOC 2007 的 test 。
for year, image_set in ('2012', 'train'), ('2012', 'val'), ('2007', 'train'), ('2007', 'val'), ('2007', 'test'):
    # 定义 目标图像路径 ,格式为 dir/images/{image_set}{year} ,例如 dir/images/train2012 。
    imgs_path = dir / 'images' / f'{image_set}{year}'
    # 定义 目标标注路径 ,格式为 dir/labels/{image_set}{year} ,例如 dir/labels/train2012 。
    lbs_path = dir / 'labels' / f'{image_set}{year}'
    # 创建目标图像路径的目录,如果目录已存在则忽略( exist_ok=True ),同时创建所有必要的父目录( parents=True )。
    imgs_path.mkdir(exist_ok=True, parents=True)
    # 创建目标标注路径的目录,逻辑同上。
    lbs_path.mkdir(exist_ok=True, parents=True)

    # 打开 VOC 数据集的图像列表文件,路径为 VOCdevkit/VOC{year}/ImageSets/Main/{image_set}.txt 。这个文件包含当前数据集的图像 ID 列表。
    with open(path / f'VOC{year}/ImageSets/Main/{image_set}.txt') as f:
        # 读取文件内容,去除首尾空白字符后按空格分割,得到图像 ID 列表。
        image_ids = f.read().strip().split()
    # 遍历图像 ID 列表,使用 tqdm 显示进度条,进度条的描述为 {image_set}{year} 。
    for id in tqdm(image_ids, desc=f'{image_set}{year}'):
        # 构造 原始图像路径 ,格式为 VOCdevkit/VOC{year}/JPEGImages/{id}.jpg 。
        f = path / f'VOC{year}/JPEGImages/{id}.jpg'  # old img path
        # 构造 目标标注路径 ,将图像文件名( f.name )替换为 .txt 后缀,用于保存 YOLO 格式的标注文件。
        lb_path = (lbs_path / f.name).with_suffix('.txt')  # new label path

        # Path.rename(target)
        # 在 Python 的 pathlib 模块中, Path.rename() 是一个方法,用于将文件或目录从一个路径重命名为另一个路径。它是 pathlib.Path 类的一部分,提供了面向对象的方式来操作文件系统路径。
        # 参数 :
        # source :调用 rename() 方法的 Path 对象,表示要被重命名的文件或目录的原始路径。
        # target :目标路径,表示重命名后的文件或目录的路径。
        # 功能 :
        # rename() 方法将文件或目录从 source 路径移动到 target 路径。如果目标路径已经存在 :
        # 如果目标路径是一个文件,它会被覆盖。
        # 如果目标路径是一个目录,行为取决于操作系统。在某些系统中,会抛出错误;在其他系统中,可能会将文件移动到该目录下。
        # 返回值 :
        # rename() 方法返回一个新的 Path 对象,表示目标路径。
        # 注意事项 :
        # 覆盖文件 :如果目标路径已经存在, rename() 会覆盖目标文件。
        # 跨文件系统移动 :在某些操作系统中,如果 source 和 target 不在同一个文件系统上,可能会抛出错误。在这种情况下,可以先复制文件,然后删除原始文件。
        # 权限问题 :如果目标路径的目录不可写, rename() 会抛出 PermissionError 。

        # 将原始图像移动到目标图像路径。 rename 方法会将文件从原始路径移动到新路径。
        f.rename(imgs_path / f.name)  # move image
        # 调用 convert_label 函数,将 VOC 格式的标注文件转换为 YOLO 格式,并保存到目标标注路径。
        convert_label(path, lb_path, year, id)  # convert labels to YOLO format
# 这段代码的主要功能是将 VOC 数据集的图像和标注文件从原始格式转换为 YOLO 格式,并重新组织到指定的目录结构中。具体步骤如下。遍历 VOC 数据集的不同年份和数据集类型。创建目标图像和标注文件的目录。读取每个数据集的图像 ID 列表。遍历图像 ID,将原始图像移动到目标目录。调用 convert_label 函数,将 VOC 格式的标注文件转换为 YOLO 格式,并保存到目标路径。通过这种方式,代码实现了 VOC 数据集到 YOLO 格式的转换,同时将文件组织到适合 YOLO 训练的目录结构中。

相关文章:

  • 目录遍历文件包含测试
  • 精品整理-2025 DeepSeek核心技术解析与实践资料合集(24份)
  • 类中的流操作符的重载
  • Python 数据可视化(一)熟悉Matplotlib
  • python判断、循环、range语句
  • Servlet简介
  • 2025最新Nginx高频面试题
  • Python的pdf2image库将PDF文件转换为PNG图片
  • windous 下 ollama 迁移到 D 盘
  • 【2025年2月28日稳定版】小米路由器4C刷机Immortalwrt 23.05.4系统搭载mentohust 0.3.1插件全记录
  • 【Mark】记录用宝塔+Nginx+worldpress+域名遇到的跨域,301,127.0.0.1,CSS加载失败问题
  • 如何流畅访问github
  • 架构案例:从初创互联网公司到分布式存储与反应式编程框架的架构设计
  • 2011-2019年各省移动电话普及率数据
  • Deepseek对ChatGPT的冲击?
  • (平衡二叉树 判断是否为AVL树 )leetcode110
  • Python 模块与包:从零到自定义的全面指南
  • 第五章 activiti流程 “权限与部署指挥部”
  • Zotero外接通义千问 API进行翻译
  • 跟着源码实现LevelDB(二)util/status.cc
  • 如何用wp做企业网站/品牌运营管理公司
  • 网站建设需求模版/青岛官网优化
  • 重庆市建设岗培中心网站/seo长沙
  • 做t恤网站 一件也可以做/网站代运营多少钱一个月
  • wordpress backupbuddy/重庆seo主管
  • 亳州企业网站建设/最近最火的关键词