自动化迁移和更新物体检测XML数据集

引言

当处理大规模的图片数据集,尤其是在物体识别和计算机视觉领域时,有效管理和更新数据集变得非常重要。在本文中,我们将介绍一个简单的Python脚本,该脚本自动化了迁移和更新标注过的XML数据集的过程。

脚本概览

该脚本进行了以下操作:

  • 遍历给定目录下的所有XML注释文件。
  • 为每个注释文件创建对应的拷贝,并更新文件路径和名字。
  • 单独处理每个XML文件中的物体注释,保持标注信息不变。
  • 拷贝原图像文件到新的目录,并更新文件名。
  • 在终端输出处理进度,包括拷贝的图片和XML文件计数器。
  • 把独特的标签类别以及总计数保存到文本文件中。

使用场景

  • 更新数据集目录结构。
  • 从图片中提取注释信息,用于机器学习模型的训练。
  • 快速获取数据集的整体信息,包括包含了哪些类别。

代码解析

设置

在脚本的开始部分,我们首先导入必要的模块,并定义源目录和目标目录的路径。

复制代码
import xml.etree.ElementTree as ET
from datetime import datetime
import os, cv2, time, shutil

这些模块包括操作XML文件的ElementTree,进行文件操作的os和shutil,还有处理图片的cv2等。

功能函数

脚本中定义了两个重要的函数来处理XML文件的创建和物体标记的添加。

复制代码
def create_object(root, xi, yi, xa, ya, obj_name):
    # 创建物体标记代码
    # ...

def create_tree(sources, image_name, h, w):
    # 创建XML文件树结构
    # ...

主循环

在主循环中,脚本读取每个注释文件,并对每个文件执行一系列操作:

复制代码
for xml in annotation_list:
    # ... 每个文件的处理逻辑...

这包括通过OpenCV获取图片尺寸,使用shutil.copyfile拷贝图片文件,解析XML文件以读取和复制物体标注信息。

结果记录

脚本最后输出处理的总数,并将数据类别及其计数保存在文本文件中:

复制代码
print(count)
labels_list = list(set(all_labels))
labels_len = len(labels_list)
labels_str = f"this datasets have {labels_len} classes, labels list is {labels_list}"
print(labels_str)
with open("record.txt", "w") as f:
    f.write(str(count))
    f.write("\n")
    f.write(labels_str)

结论

我们介绍的脚本可以帮助用户以一种简单高效的方式来处理和准备用于物体检测的图片数据集。通过使用此脚本,用户可以节省宝贵的时间并减少手动错误,提高了数据准备工作的效率。

代码

完整脚本可以在本文附带的代码段中找到。如果你有兴趣自己尝试或者修改以适应你的项目需求,欢迎下载和使用。

复制代码
import xml.etree.ElementTree as ET
from datetime import datetime
import os, cv2, time, shutil


initial_dir_orin = "E:\\lindsay\\voc_dataset_kitchen"
now = datetime.now()
year = str(now.year)
month = str(now.month).zfill(2)
day = str(now.day).zfill(2)
time_path = year+month+day
initial_dir_orin_flag = time_path+"_"+str(time.time())
annotations_path = initial_dir_orin+"/annotations"
images_path = initial_dir_orin+"/images"

new_images_path = time_path+"_repaire_datasets"+"/images"
new_annotations_path = time_path+"_repaire_datasets"+"/annotations"

if not os.path.exists(new_images_path):
    os.makedirs(new_images_path)


if not os.path.exists(new_annotations_path):
    os.makedirs(new_annotations_path)
all_labels = []
annotation_list = os.listdir(annotations_path)
print(len(annotation_list))
count = 0
# 定义一个创建一级分支object的函数
def create_object(root, xi, yi, xa, ya, obj_name):  # 参数依次,树根,xmin,ymin,xmax,ymax
    # 创建一级分支object
    _object = ET.SubElement(root, 'object')
    # 创建二级分支
    name = ET.SubElement(_object, 'name')
    # print(obj_name)
    name.text = str(obj_name)
    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
    bndbox = ET.SubElement(_object, 'bndbox')
    xmin = ET.SubElement(bndbox, 'xmin')
    xmin.text = '%s' % xi
    ymin = ET.SubElement(bndbox, 'ymin')
    ymin.text = '%s' % yi
    xmax = ET.SubElement(bndbox, 'xmax')
    xmax.text = '%s' % xa
    ymax = ET.SubElement(bndbox, 'ymax')
    ymax.text = '%s' % ya


# 创建xml文件的函数
def create_tree(sources, image_name, h, w):
    imgdir = sources.split('/')[-1]
    # 创建树根annotation
    annotation = ET.Element('annotation')
    # 创建一级分支folder
    folder = ET.SubElement(annotation, 'folder')
    # 添加folder标签内容
    folder.text = (imgdir)

    # 创建一级分支filename
    filename = ET.SubElement(annotation, 'filename')
    filename.text = image_name

    # 创建一级分支path
    path = ET.SubElement(annotation, 'path')

    path.text = '{}/{}'.format(sources, image_name)  # 用于返回当前工作目录

    # 创建一级分支source
    source = ET.SubElement(annotation, 'source')
    # 创建source下的二级分支database
    database = ET.SubElement(source, 'database')
    database.text = 'Unknown'

    # 创建一级分支size
    size = ET.SubElement(annotation, 'size')
    # 创建size下的二级分支图像的宽、高及depth
    width = ET.SubElement(size, 'width')
    width.text = str(w)
    height = ET.SubElement(size, 'height')
    height.text = str(h)
    depth = ET.SubElement(size, 'depth')
    depth.text = '3'

    # 创建一级分支segmented
    segmented = ET.SubElement(annotation, 'segmented')
    segmented.text = '0'
    return annotation

for xml in annotation_list:
    count = count+1
    img = xml.split(".xml")[0]
    image = os.path.join(images_path,img+".jpg")
    annotation = os.path.join(annotations_path,xml)
    img1 = cv2.imread(image)
    height, width, _ = img1.shape
    new_image = os.path.join(new_images_path,initial_dir_orin_flag+"_"+str(count)+".jpg")
    new_annotation = os.path.join(new_annotations_path, initial_dir_orin_flag+"_"+str(count)+".xml")
    shutil.copyfile(image, new_image)
    annotation_create = create_tree(new_images_path,initial_dir_orin_flag+"_"+str(count)+".jpg", height, width)
    print(annotation)
    tree = ET.parse(annotation)
    root = tree.getroot()
    objects = root.findall('object')
    for i, obj in enumerate(objects):
        label = obj.find('name').text
        bb = obj.find('bndbox')
        x1 = int(bb.find('xmin').text)
        y1 = int(bb.find('ymin').text)
        x2 = int(bb.find('xmax').text)
        y2 = int(bb.find('ymax').text)
        print(x1, y1, x2, y2, label, end = '\t|\t')
        all_labels.append(label)
        create_object(annotation_create, x1, y1, x2, y2, label)
    tree = ET.ElementTree(annotation_create)
    tree.write(new_annotation)
    print("\n")
print(count)

labels_list = list(set(all_labels))
labels_len = len(labels_list)
labels_str = f"this datasets have {labels_len} classes, labels list is {labels_list}"
print(labels_str)
with open("record.txt", "w") as f:
    f.write(str(count))
    f.write("\n")
    f.write(labels_str)

和任何自动化处理一样,使用这个脚本时,你应该先在少量文件上测试来确保它按预期执行,以避免意外的数据丢失或损坏。希望这个脚本和博客对你的项目有所帮助!

相关推荐
七夜zippoe1 小时前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
Fcy6483 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满3 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
代码游侠3 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
Harvey9033 小时前
通过 Helm 部署 Nginx 应用的完整标准化步骤
linux·运维·nginx·k8s
介一安全4 小时前
【Web安全】XML注入全手法拆解
xml·web安全·安全性测试
珠海西格电力科技4 小时前
微电网能量平衡理论的实现条件在不同场景下有哪些差异?
运维·服务器·网络·人工智能·云计算·智慧城市
释怀不想释怀4 小时前
Linux环境变量
linux·运维·服务器
zzzsde5 小时前
【Linux】进程(4):进程优先级&&调度队列
linux·运维·服务器
聆风吟º6 小时前
CANN开源项目实战指南:使用oam-tools构建自动化故障诊断与运维可观测性体系
运维·开源·自动化·cann