数据集格式转化

news2024/11/13 15:21:47

数据集格式转换的要点是从对应的格式中解析出对应的classbbox

整体说明:

  • lables_voc_dir: 为存放所有xml的标注文件夹,
  • labels_yolo_dir: 为转换后存放所有xml的标注文件夹
  • images_dir : 为所有图像文件的文件夹。、

注意:代码部分可以不要看,重点关注调用函数的接口

以下代码资源

一. VOC 转YOLO

import os
import random
import shutil
import glob
from PIL import Image
import xml.etree.ElementTree as ET

def convert_xml_to_txt_format(xml_file_path: str, class_list: list) -> list:
    """
    将单个xml文件转换为txt格式。

    参数:
    xml_file_path (str): XML文件的路径。
    class_list (list): 包含所有类别的列表。

    返回:
    list: 包含YOLO格式的标签列表。
    """
    # 根据class_list构建class_to_id_map
    class_to_id_map = {class_name: index for index, class_name in enumerate(class_list)}

    tree = ET.parse(xml_file_path)
    root = tree.getroot()

    width = int(root.find('.//size/width').text)
    height = int(root.find('.//size/height').text)

    txt_format = []
    for obj in root.findall('.//object'):
        class_name = obj.find('name').text
        if class_name not in class_to_id_map:
            continue
        class_id = class_to_id_map[class_name]
        bbox = obj.find('bndbox')
        xmin = float(bbox.find('xmin').text)
        ymin = float(bbox.find('ymin').text)
        xmax = float(bbox.find('xmax').text)
        ymax = float(bbox.find('ymax').text)

        x_center = (xmin + xmax) / 2 / width
        y_center = (ymin + ymax) / 2 / height
        bbox_width = (xmax - xmin) / width
        bbox_height = (ymax - ymin) / height

        txt_format.append(f"{class_id} {x_center} {y_center} {bbox_width} {bbox_height}")

    return txt_format



def write_yolo_format_labels_to_file(yolo_label_path: str,  yolo_content: list):
    """
    将YOLO格式的标签写入到文件。

    参数:
    yolo_label_path (str): YOLO标签文件的名称。
    yolo_content (list): 包含YOLO格式标签的列表。
    """
    with open(yolo_label_path, 'w') as f:
        for line in yolo_content:
            f.write(line + '\n')


def convert_voc2yolo(voc_annotations_dir: str, yolo_labels_dir: str, class_list: list):
    """
    将VOC格式的XML注释转换为YOLO格式的注释。

    参数:
    voc_annotations_dir (str): VOC注释目录的路径。
    yolo_labels_dir (str): YOLO标签目录的路径。
    class_list (list): 类别名称的list。
    """
    if not os.path.exists(yolo_labels_dir):
        os.makedirs(yolo_labels_dir)

    for xml_file in os.listdir(voc_annotations_dir):
        if xml_file.endswith('.xml'):
            yolo_label_path = os.path.join(yolo_labels_dir,xml_file.replace('.xml', '.txt'))
            xml_file_path = os.path.join(voc_annotations_dir, xml_file)

            yolo_content = convert_xml_to_txt_format(xml_file_path,class_list)
            write_yolo_format_labels_to_file(yolo_label_path, yolo_content)
    with open(os.path.join(yolo_labels_dir,"classes.txt"),"w",encoding='utf-8') as f:
        for c in class_list:
            f.write(c+'\n')

如下代码所示:lables_voc_dir: 为存放所有xml的标注文件夹,labels_yolo_dir: 为转换后存放所有xml的标注文件夹,class_names为类别列表,当调用convert_voc2yolo()后会labels_yolo_dir目录下会生成所有的txt文件。

if __name__ == "__main__":
    dataset_dir = "./dataset"
    labels_voc_dir = "labels_voc"
    labels_yolo_dir = "labels_yolo"
    class_names = ["橘子", "香蕉", "草莓"]
    convert_voc2yolo(labels_voc_dir,labels_yolo_dir,class_names)

二. YOLO转VOC

import os
import random
import shutil
import glob
from PIL import Image
import xml.etree.ElementTree as ET

def convert_txt_to_xml_format(txt_file_path: str, voc_file_path: str, class_names: list, images_dir: str):
    """
    将单个txt文件转换为xml格式。

    参数:
    txt_file_path (str): YOLO标签文件txt的路径。
    voc_file_path (str): XML文件的路径。
    class_names (list): 包含类别名称的列表。
    images_dir (str): 包含图像文件的目录路径。
    """
    with open(txt_file_path, 'r') as file:
        lines = file.readlines()

    # 获取txt文件的文件名,然后去掉后缀
    txt_filename = os.path.basename(txt_file_path)
    txt_filename_without_ext = os.path.splitext(txt_filename)[0]

    # 使用glob库在images_dir下搜索与txt文件同名的图片文件
    pattern = os.path.join(images_dir, f"{txt_filename_without_ext}.*")
    matching_files = glob.glob(pattern)

    if not matching_files:
        raise FileNotFoundError(f"No matching image found for {txt_filename_without_ext} in {images_dir}")

    img_file = matching_files[0]  # 假设找到的第一个匹配文件就是正确的图片

    # 从与YOLO标签同名的图像文件中读取宽度和高度
    img = Image.open(img_file)
    width, height = img.size

    root = ET.Element("annotation")

    folder = ET.SubElement(root, "folder")
    folder.text = os.path.basename(images_dir)

    filename = ET.SubElement(root, "filename")
    filename.text = os.path.basename(img_file)

    path = ET.SubElement(root, "path")
    path.text = os.path.abspath(img_file)

    source = ET.SubElement(root, "source")
    database = ET.SubElement(source, "database")
    database.text = "Unknown"

    size = ET.SubElement(root, "size")
    ET.SubElement(size, "width").text = str(width)
    ET.SubElement(size, "height").text = str(height)
    ET.SubElement(size, "depth").text = "3"

    segmented = ET.SubElement(root, "segmented")
    segmented.text = "0"

    for line in lines:
        values = line.strip().split()
        if len(values) < 5:
            continue

        class_id, x_center, y_center, bbox_width, bbox_height = map(float, values)

        object = ET.SubElement(root, "object")
        name = ET.SubElement(object, "name")
        name.text = class_names[int(class_id)]

        pose = ET.SubElement(object, "pose")
        pose.text = "Unspecified"

        truncated = ET.SubElement(object, "truncated")
        truncated.text = "0"

        difficult = ET.SubElement(object, "difficult")
        difficult.text = "0"

        bndbox = ET.SubElement(object, "bndbox")
        xmin = int((x_center - bbox_width / 2) * width)
        ymin = int((y_center - bbox_height / 2) * height)
        xmax = int((x_center + bbox_width / 2) * width)
        ymax = int((y_center + bbox_height / 2) * height)
        ET.SubElement(bndbox, "xmin").text = str(xmin)
        ET.SubElement(bndbox, "ymin").text = str(ymin)
        ET.SubElement(bndbox, "xmax").text = str(xmax)
        ET.SubElement(bndbox, "ymax").text = str(ymax)

    # 使用prettify函数来格式化输出
    pretty_xml_as_string = prettify(root)
    with open(voc_file_path, 'w', encoding='utf-8') as f:
        f.write(pretty_xml_as_string)


def prettify(elem):
    from xml.dom import minidom
    """Return a pretty-printed XML string for the Element."""
    rough_string = ET.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="	")


def convert_yolo2voc(yolo_labels_dir: str, voc_labels_dir: str, images_dir: str, class_list: list):
    """
    将YOLO格式的标签文件夹转换为VOC格式的XML注释文件夹。

    参数:
    yolo_labels_dir (str): YOLO标签文件夹的路径。
    voc_labels_dir (str): 转换后的VOC XML文件夹的路径。
    images_dir (str): 包含图像文件的目录路径。
    class_names (list): 包含类别名称的列表。
    """
    # 确保voc_labels_dir存在
    if not os.path.exists(voc_labels_dir):
        os.makedirs(voc_labels_dir)

    # 遍历YOLO标签文件夹
    for label_file in os.listdir(yolo_labels_dir):
        if label_file.endswith(".txt"):
            yolo_file_path = os.path.join(yolo_labels_dir, label_file)
            voc_file_path = os.path.join(voc_labels_dir, label_file.replace(".txt", ".xml"))
            convert_txt_to_xml_format(yolo_file_path, voc_file_path, class_list, images_dir)

如下代码所示:lables_voc_dir: 为转换后存放所有xml的标注文件夹,labels_yolo_dir: 为存放所有xml的标注文件夹,class_names为类别列表,当调用convert_voc2yolo()后会labels_voc_dir目录下会生成所有的txt文件。

if __name__ == "__main__":
    labels_voc_dir = "labels_voc"
    labels_yolo_dir = "labels_yolo"
    imgs_dir="imgs"
    class_names = ["橘子", "香蕉", "草莓"]
    convert_yolo2voc(labels_yolo_dir,labels_voc_dir,imgs_dir,class_names)


三. Json 转YOLO

提示:可以采用 data_df = pd.read_json(json_path),然后利用pandas的语法进行提取bbox和class_id

四. 划分数据集

def split_dataset(images_origin_dir: str, labels_origin_dir: str, dataset_dir: str, train_ratio: float = 0.8):
    """
    将原始数据集分割为训练集和验证集,并将相应的文件复制到新的文件夹中。

    参数:
    images_origin_dir (str): 存放所有图片文件夹路径
    labels_origin_dir (str): 存放所有标签文件夹路径。
    dataset_dir (str): 新的数据集根目录。
    train_ratio (float, optional): 训练集的比例,默认为 0.8。
    """
    images_dir = os.path.join(dataset_dir, "images")
    labels_dir = os.path.join(dataset_dir, "labels")
    train_dir = os.path.join(images_dir, "train")
    val_dir = os.path.join(images_dir, "val")

    # 创建训练集和验证集的文件夹
    os.makedirs(train_dir, exist_ok=True)
    os.makedirs(val_dir, exist_ok=True)
    os.makedirs(os.path.join(labels_dir, "train"), exist_ok=True)
    os.makedirs(os.path.join(labels_dir, "val"), exist_ok=True)

    image_files=[]
    for file in os.listdir(images_origin_dir):
        if file.endswith(".jpg") or file.endswith(".png") or file.endswith(".jpeg"):
            image_files.append(os.path.join(images_origin_dir, file))

    # 使用 random.sample 函数进行随机划分
    random.seed(42)  # 设置随机种子
    train_images = random.sample(image_files, k=int(len(image_files) * train_ratio))
    val_images = [f for f in image_files if f not in train_images]

    # 复制文件到训练集和验证集文件夹
    for subset, images in [('train', train_images), ('val', val_images)]:
        for image_file in images:
            # 复制图片文件
            target_image_path = os.path.join(images_dir, subset, os.path.basename(image_file))
            shutil.copyfile(image_file, target_image_path)

            # 复制标签文件
            label_file = os.path.splitext(os.path.basename(image_file))[0] + '.txt'
            label_path = os.path.join(labels_origin_dir, label_file)
            if os.path.exists(label_path):
                target_label_path = os.path.join(labels_dir, subset, label_file)
                shutil.copyfile(label_path, target_label_path)

    print(f"训练集大小: {len(train_images)}")
    print(f"验证集大小: {len(val_images)}")

如下代码所示:dataset_dir:为待生成数据集的根目录,imgs_dir:为存放所有图片的根目录,labels_yolo:为存放所有txt的根目录,调用split_dataset()以后,会生成如下的目录结构:
在这里插入图片描述

if __name__ == "__main__":

    dataset_dir = "./dataset"
    imgs_dir="imgs"
    labels_yolo_dir = "labels_yolo"
    split_dataset(imgs_dir,labels_yolo_dir,dataset_dir)


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2095329.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++手撕简易list

目录 节点的准备 list类 push_back stl容器的遍历和修改 begin end ! 重载* 效果展示&#xff1a; const迭代器 方法一&#xff1a; 方法二&#xff1a; ->的重载 insert push_front erase 展示效果 pop_back && pop_front 效果展示 clear&am…

【 html+css 绚丽Loading 】000030 灵文闪烁符

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

【C++】继承相关知识详细梳理

1.继承简介 什么是继承&#xff1a; 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。 继承呈现了面向对象程序设计的层…

python破解[5分钟解决拼多多商家后台字体加密]

可【QQ群】拿源码 进入经营总览想把数据存下来发现返回的json数据部分空白如下 这可怎么办 稳住应该是字体的问题&#xff0c;可能是多多自己实现了某种字体&#xff0c;我们去找他的js 发现如我们所想&#xff0c;进行跟踪&#xff0c;发现的确是在css端进行了字体替换&am…

报警规范管理

报警规则管理 想要获取报警数据&#xff0c;我们首先必须先制定报警规则&#xff0c;会根据不同的设备&#xff0c;不同的物模型来定义报警规则 需求分析 我们先来分析需求&#xff0c;打开原型图 数据来源&#xff1a; 逻辑规则&#xff1a; 1&#xff09;若多条报警规则是…

CSS-层叠上下文【看这一篇就够了!!!】

目录 前序 z-index设置定位元素层叠顺序 z-index值相同时&#xff0c;写在后面的覆盖写在前面的 z-index值越大&#xff0c;越在上面显示 z-index值为负数 CSS中的层叠上下文 什么是“层叠上下文” 层叠上下文的创建 根层叠上下文 定位元素的传统层叠上下文 层叠顺序…

15:发光二极管布局要求

1.指示灯一般放正面&#xff0c; 靠板边

【Android】Material Design编写更好的UI

Toolbar 对于控件ActionBar我们非常熟悉&#xff0c;就是我们常见的标题栏&#xff0c;但ActionBar只能位于活动的顶部&#xff0c;因此我们更建议使用Toolbar。在新建一个项目的时候都是默认显示ActionBar&#xff0c;我们要使用Toolbar就需要先将标题栏改为不显示 先来看看…

在Ubuntu上使用apt工具安装RabbitMQ

创建安装脚本 cd home/ madir scripts cd scripts 创建脚本前&#xff0c;需要确认Linux版本。不同的版本对应着不同的运行脚本。 lsb_release -a 查看Linux版本 可以看到&#xff0c;我的Ubuntu版本是22.04。 在这里找到对应的脚本复制。 创建脚本文件&#xff1a; ca…

详解树状数组(C/C++)

树状数组&#xff08;Binary Indexed Tree&#xff0c;简称BIT或Fenwick Tree&#xff09;是一种用于高效处理数据序列的算法数据结构。它能够支持两个主要操作&#xff1a;单点更新和区间求和&#xff0c;这两个操作的时间复杂度都能达到O(log n)&#xff0c;其中 n 是数据序列…

STM32基础篇:SPI片上外设

SPI外设简介 STM32芯片内部集成了SPI片上外设&#xff0c;可由硬件自动执行时钟生成、数据收发等功能&#xff0c;减轻CPU负担。对于STM32F103C8T6&#xff0c;其SPI资源有SPI1、SPI2。 一些参数配置&#xff1a; 8位/16位数据帧高位先行/低位先行时钟频率&#xff1a;PCLK/…

vue3本地运行错误集

1、解决报错ValidationError: Progress Plugin Invalid Options问题 ValidationError: Progress Plugin Invalid Optionsoptions should NOT have additional propertiesoptions should NOT have additional propertiesoptions should NOT have additional propertiesoptions …

SMART PLC 脉冲输出指令PLS应用

200SMART PLC如何实现可调频率可调占空比PWM输出 200smart_PLC如何实现可调频率可调占空比PWM输出_200smart pwm-CSDN博客文章浏览阅读6.4k次,点赞2次,收藏7次。本文介绍了如何在SMART PLC中通过修改原向导接口,实现可调频率和占空比的PWM输出。详细阐述了脉冲周期、占空比…

DMA简述与使用实例

之后要学&#xff1a;SPI / IICDMA 学习的这位up主的视频&#xff1a;全网最清楚的DMA讲解&#xff0c;三种搬运模式三个例子讲清楚&#xff08;STM32教程基于HAL库和CUBEIDE&#xff09;_哔哩哔哩_bilibili 目录 01-基本信息 1-概述 2-方向 3-模式 正常模式 轮询模式 …

学习日志8.30--防火墙NAT

目录 一、实验环境配置 二、配置防火墙静态NAT一对一 三、配置防火墙静态NAT多对多 四、配置防火墙NAT端口转换NAPT 五、防火墙smart-nat、easyip 六、防火墙三元组NAT 在学习过基于路由器的NAT网络地址转换&#xff0c;现在学习基于防火墙NAT的网络地址转换&#xff0c;…

python-读写Excel:xlwings库操作

几种操作Excel的python库对比 安装:pip install xlwings 目录 APP实例化对象 工作薄对象 创建工作薄 打开工作薄 工作薄属性 工作表对象 新增工作表 复制表 获取工作表对象 工作表属性 删除和清除表数据及表格式 工作表行高列宽(自动调整) 单元格对象 获取单元…

【hot100篇-python刷题记录】【旋转图像】

R7-矩阵篇 印象题&#xff1a; 思路&#xff1a; 先转置&#xff0c;转置完我们按照列的中间进行对称交换就可以了。 class Solution:def rotate(self, matrix: List[List[int]]) -> None:"""Do not return anything, modify matrix in-place instead.&qu…

【微机原理】指令JZ和JNZ的区别

&#x1f31f; 嗨&#xff0c;我是命运之光&#xff01; &#x1f30d; 2024&#xff0c;每日百字&#xff0c;记录时光&#xff0c;感谢有你一路同行。 &#x1f680; 携手启航&#xff0c;探索未知&#xff0c;激发潜能&#xff0c;每一步都意义非凡。 JZ&#xff08;Jump …

祝贺严建兵教授任华中农业大学校长

公众号&#xff1a;生信漫谈&#xff0c;获取最新科研信息&#xff01; 祝贺严建兵教授任华中农业大学校长https://mp.weixin.qq.com/s?__bizMzkwNjQyNTUwMw&mid2247487040&idx1&sn6800055c9944754be11dc77a30ee1906&chksmc0e9ebb0f79e62a64634d5cd057578ca5…

Java 入门指南:Java 并发编程 —— AQS、AQLS、AOS 锁与同步器的框架

AQS AQS 是 AbstractQueuedSynchronizer 的缩写&#xff0c;即 抽象队列同步器&#xff0c;是 Java.util.concurrent 中的一个基础工具类&#xff0c;用于实现同步器&#xff08;Synchronizer&#xff09;的开发。 AQS 提供了一种实现锁和同步器的框架&#xff0c;使用 AQS 能…