tjdnbj 2024-08-18 09:45 采纳率: 36.8%
浏览 5

YOLOV5数据标注询问

当前代码适用的是images文件夹里全为图片且annotations中每一个txt文件对应每一个图片的信息。请问如果我的images文件夹里包含多个文件夹,annotations中每一个txt包含多条信息,对应每一个文件夹里的每一张图片的信息,该如何修改以下代码呢?

from PIL import Image
import os

from os import walk
# 指定图片目录 - 根据需要更改为训练集(train)、验证集(val)和测试集(test-dev)的路径
image_dir = "VisDrone2019-VID-val/sequences/"
annot_dir = "VisDrone2019-VID-val/annotations/"
output_dir = "
![img](https://img-mid.csdnimg.cn/release/static/image/mid/ask/92cc982645a04f7fbdf6d4faaf103afe.png "#left")
VisDrone2019-VID-val/labels/"
remove_ignored = True  # 是否移除被标记为忽略的标注



# 如果输出目录不存在,则创建该目录
if not os.path.exists(output_dir):
    os.makedirs(output_dir)


def convert_annotation(img_size, bbox):
    """
    将VisDrone的边界框格式转换为YOLO的边界框格式(中心点坐标+宽高)
    参数:
    - img_size: 图像的尺寸,格式为(width, height)
    - bbox: VisDrone的边界框,格式为[x_min, y_min, width, height]
    返回:
    - 转换后的YOLO格式边界框,格式为[x_center, y_center, width, height],值被归一化
    """
    width_div = 1.0 / img_size[0]
    height_div = 1.0 / img_size[1]
    return [(bbox[0] + bbox[2] / 2) * width_div, (bbox[1] + bbox[3] / 2) * height_div, bbox[2] * width_div,
            bbox[3] * height_div]


# 遍历标注目录中的所有文件
for annot_file in os.listdir(annot_dir):
    annot_path = os.path.join(annot_dir, annot_file)
    if not os.path.isfile(annot_path):
        continue

    base_name = os.path.splitext(annot_file)[0]
    image_folder_path = os.path.join(image_dir, base_name)

    if not os.path.exists(image_folder_path):
        print(f"Image folder not found: {image_folder_path}")
        continue

    # 获取图像文件列表,并按文件名排序
    image_files = sorted([f for f in os.listdir(image_folder_path) if f.lower().endswith('.jpg')])

    # 创建输出目录(如果不存在)
    output_folder = os.path.join(output_dir, base_name)
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    with open(annot_path, 'r', encoding='utf8') as f:
        for index, line in enumerate(f):
            data = line.strip().split(',')
            if len(data) < 6:
                continue

            # 获取图像文件名
            if index < len(image_files):
                image_file = image_files[index]
            else:
                print(f"Not enough images for annotation file: {annot_path}")
                continue

            image_path = os.path.join(image_folder_path, image_file)
            output_path = os.path.join(output_folder, f"{os.path.splitext(image_file)[0]}.txt")

            print(f"Processing image file: {image_path}")

            if not os.path.exists(image_path):
                print(f"Image file not found: {image_path}")
                continue

            img = Image.open(image_path)
            class_label = int(data[5]) - 1  # 假设YOLO的类别范围为0-90表示行人,9表示摩托车

            if remove_ignored:
                considered = data[4]  # 如果需要移除被忽略的标注,则检查当前标注是否被考虑
            else:
                considered = 1  # 如果不移除被忽略的标注,则考虑所有标注

            if considered != str(0) and (class_label >= 0) and (class_label <= 9):  # 检查是否为有效类别
                bounding_box_visdrone = [float(x) for x in data[1:5]]
                yolo_bounding_box = convert_annotation(img.size, bounding_box_visdrone)
                bounding_box_string = " ".join([str(x) for x in yolo_bounding_box])  # 创建要写入的标注字符串

                with open(output_path, 'w', encoding='utf-8') as output_file:
                    output_file.write(f"{class_label} {bounding_box_string}\n")  # 以YOLO格式写入转换后的标注和类别


img

img

  • 写回答

2条回答 默认 最新

  • 何事_ 2024-08-18 09:46
    关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    你的代码目前假设图像文件和标注文件是一一对应的,即每一个图像文件夹内只有一个图像文件,并且该图像文件有一个对应的标注文件。但从你提供的图2和图3来看,每一个标注文件似乎对应多个图像文件。因此,你需要对代码进行一些修改以适应这种情况。

    假设你的目录结构如下:

    VisDrone2019-VID-val/
    │
    ├── sequences/
    │   ├── uav000008600000v/
    │   │   ├── image1.jpg
    │   │   ├── image2.jpg
    │   │   └── ...
    │   ├── uav0000117_02622_v/
    │   │   ├── image1.jpg
    │   │   ├── image2.jpg
    │   │   └── ...
    │   └── ...
    ├── annotations/
    │   ├── uav000008600000v.txt
    │   ├── uav000117_02622_v.txt
    │   └── ...
    └── labels/
    

    在这种情况下,你可以按照以下步骤修改代码:

    1. 遍历sequences目录中的所有子目录。
    2. 对于每个子目录,检查其是否有对应的标注文件在annotations目录中。
    3. 如果有,读取该标注文件并处理其中的每一行。每一行应该对应一个图像文件的标注。
    4. 对于每一行中的标注,找到对应的图像文件(基于文件名),然后进行转换并写入到labels目录。

    下面是一个简化的代码结构来帮助你理解:

    import os
    from PIL import Image
    from your_script import convert_annotation  # 假设你已经定义了此函数
    
    image_dir = "VisDrone2019-VID-val/sequences/"
    annot_dir = "VisDrone2019-VID-val/annotations/"
    output_dir = "VisDrone2019-VID-val/labels/"
    remove_ignored = True  # 是否移除被标记为忽略的标注
    
    # 遍历所有序列目录
    for sequence_dir in os.listdir(image_dir):
        sequence_path = os.path.join(image_dir, sequence_dir)
        if not os.path.isdir(sequence_path):
            continue
        
        # 获取序列名称(例如:uav000008600000v)用于查找对应的标注文件
        sequence_name = sequence_dir.split('_')[0]  # 根据你的实际情况调整这部分代码以获取正确的序列名称
        annot_file = os.path.join(annot_dir, f"{sequence_name}.txt")  # 根据序列名称构建标注文件的路径
        if not os.path.exists(annot_file):
            print(f"No annotation file found for sequence: {sequence_name}")
            continue
        
        with open(annot_file, 'r', encoding='utf8') as f:
            for line in f:
                data = line.strip().split(',')  # 根据你的实际情况调整这部分代码以解析标注文件的内容
                if len(data) < 6:  # 假设每一行至少有6个字段(根据实际情况调整)
                    continue  # 如果行数不够则跳过当前行(你可能需要根据实际情况进行更多检查)
                image_file = data[index]  # 获取当前行的图像文件名(index取决于你的数据格式)你可能需要调整这部分代码以正确获取文件名。这里只是一个示例。假设文件名在最后一个字段之前。如果数据格式不同,请相应地调整这部分代码。你也可以使用其他方式来找到文件名和标注行的对应关系,比如根据序列编号和图片编号结合来生成文件名等。使用更稳健的方式来确保文件的匹配是很重要的。另外确保在使用之前确认index是否正确以避免出现索引越界错误等问题。然后根据其他数据和给定的逻辑继续你的转换逻辑和输出处理逻辑... (具体代码细节还需要根据实际的数据格式来进一步开发和测试。)根据你提供的数据格式和你的需求进行具体的处理。这个过程涉及到很多细节和复杂性,包括确保文件的匹配关系正确等,所以需要仔细地检查和测试以确保结果的准确性。由于具体的细节可能涉及很多变化和不一致性,因此这里只是一个基本的框架和思路供你参考。具体的实现需要根据你的实际情况进行调整和测试。
    
    评论

报告相同问题?

问题事件

  • 创建了问题 8月18日