半自动标注yolo训练数据并逆向为Labelimg标注文件

1. 半自动标注 YOLO 数据的原理与方法

  • 模型辅助标注:首先,通过训练一个初步的 YOLO 模型,使其能够识别出大致的目标。这一步通常是基于少量手动标注的数据集进行训练。
  • 推理辅助标注:将初步训练的 YOLO 模型应用于新图像,生成初步的检测结果,这些检测框会作为半自动标注的基础。
  • 手动校正:对于模型生成的标注框,使用标注工具(如 LabelImg 等)进行必要的手动微调和修正,以提高标注的准确性。

2. 将 YOLO 格式标注转换为 LabelImg 格式的流程

  • YOLO 格式与 PASCAL VOC 格式的区别:介绍 YOLO 使用的是相对坐标的格式,而 LabelImg 使用的 PASCAL VOC XML 格式是绝对坐标。
  • 坐标转换:在生成 YOLO 标注时,坐标是归一化的中心点坐标和宽高,而在生成 LabelImg 的 XML 文件时,需要将这些坐标转换成左上角和右下角的像素坐标。
  • 类别映射:解释如何将 YOLO 的类别 ID 与具体的类别名称对应,并在生成的 XML 文件中正确写入。

3. 自动化脚本示例

  • 博客通常会提供一段 Python 脚本,详细说明如何从 YOLO 格式自动生成 PASCAL VOC 格式的 XML 文件。脚本可能包括:
    • 读取 YOLO 文件并解析数据:解析每个 YOLO 文件中的类别 ID 和坐标。
    • 反归一化 YOLO 坐标:将 YOLO 的中心点坐标和宽高转换为左上角和右下角的坐标。
    • 生成 XML 文件:用 PASCAL VOC XML 格式的标签信息填充每个目标对象,并将生成的 XML 文件保存在指定文件夹。

4. 实现效果与应用场景

  • 提升标注效率:解释如何利用半自动标注技术大幅减少人工标注的工作量,尤其适用于需要标注大量数据的场景。
  • 适用数据集:博客可能会提到,这种方法适用于目标比较简单且明显的数据集,例如交通标志、自然场景中的单类或少类目标。

一、Labelimg标注图像数据

pascl voc格式标注文件

二、将pascl voc 转化为yolo格式

python 复制代码
import os
import xml.etree.ElementTree as ET
import shutil

# 输入和输出路径
annotations_dir = 'F:\\trafficsigntest\\TT100K\\tt100k_2021\\tt100k_2021\\yolo\\yolonew\yololabel'  # 标注文件夹路径
images_dir = 'F:\\trafficsigntest\\TT100K\\tt100k_2021\\tt100k_2021\\yolo\\yolonew\\yolonew'  # 图像文件夹路径
output_dir = 'F:\\trafficsigntest\\TT100K\\tt100k_2021\\tt100k_2021\\yolonew'  # YOLO 格式输出文件夹

# 检查输出文件夹是否存在
os.makedirs(output_dir, exist_ok=True)
os.makedirs(os.path.join(output_dir, "images"), exist_ok=True)
os.makedirs(os.path.join(output_dir, "labels"), exist_ok=True)

# 类别映射(假设有单一类别"monostyle",否则需要更改类别)
class_mapping = {"monostyle": 0,"single_cantilever":1,"gantry":2,"road_attachment":"3","double_cantilever":4,"polystyle":5}


# 遍历 XML 文件
for xml_file in os.listdir(annotations_dir):
    if xml_file.endswith('.xml'):
        # 解析 XML 文件
        tree = ET.parse(os.path.join(annotations_dir, xml_file))
        root = tree.getroot()

        # 获取图像文件名和尺寸
        filename = root.find('filename').text
        width = int(root.find('size/width').text)
        height = int(root.find('size/height').text)

        # 生成 YOLO 格式标注
        yolo_annotations = []
        for obj in root.findall('object'):
            class_name = obj.find('name').text
            if class_name in class_mapping:
                class_id = class_mapping[class_name]

                # 获取边界框并转换为 YOLO 格式
                xmin = int(obj.find('bndbox/xmin').text)
                ymin = int(obj.find('bndbox/ymin').text)
                xmax = int(obj.find('bndbox/xmax').text)
                ymax = int(obj.find('bndbox/ymax').text)

                # 转换为 YOLO 格式坐标
                x_center = ((xmin + xmax) / 2) / width
                y_center = ((ymin + ymax) / 2) / height
                box_width = (xmax - xmin) / width
                box_height = (ymax - ymin) / height

                # 添加到标注列表
                yolo_annotations.append(f"{class_id} {x_center} {y_center} {box_width} {box_height}")

        # 写入 YOLO 格式的标注文件
        yolo_filename = os.path.splitext(filename)[0] + '.txt'
        with open(os.path.join(output_dir, "labels", yolo_filename), 'w') as f:
            f.write("\n".join(yolo_annotations))

        # 拷贝图像文件
        shutil.copy(os.path.join(images_dir, filename), os.path.join(output_dir, "images", filename))

print("转换完成!所有标注文件已转换为 YOLO 格式并拷贝对应图像文件。")

yolo 格式标注文件

三、整理为YOLO v5 模型训练格式

python 复制代码
# Ultralytics YOLOv5 🚀, AGPL-3.0 license
# COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics
# Example usage: python train.py --data coco128.yaml
# parent
# ├── yolov5
# └── datasets
#     └── coco128  ← downloads here (7 MB)

# 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, ..]
path: /home/lyy/yolo # dataset root dir
train: images/train # train images (relative to 'path') 128 images
val: images/val # val images (relative to 'path') 128 images
#test: images/test # test images (optional)
#{"monostyle": 0,"single_cantilever":1,"gantry":2,"road_attachment":"3","double_cantilever":4,"polystyle":5}

# Classes
names:
  0: monostyle
  1: single_cantilever
  2: gantry
  3: road_attachment
  4: double_cantilever
  5: polystyle

训练模型:

bash 复制代码
python train.py --data='data/tt100k_yolo.yaml'

模型预测:

bash 复制代码
python detect.py --data='data/tt100k_yolo.yaml' --weights='runs/train/exp38/weights/best.pt' --source='/common/dataset/bdd100k_images/bdd100k/images/10k/test' --name='/common/dataset/bdd100k_images/bdd100k/images/10k/exp'

四、逆向将yolo格式数据集生成labelimg标注的数据

python 复制代码
import os
import xml.etree.ElementTree as ET
from xml.dom.minidom import parseString
from PIL import Image

# # 输入和输出路径
# yolo_labels_dir = 'path/to/yolo_labels'  # YOLO格式标签路径
# images_dir = 'path/to/images'  # 原始图像路径
# output_dir = 'path/to/voc_labels'  # 输出的VOC XML文件路径

# 输入和输出路径
yolo_labels_dir = 'F:\\trafficsigntest\\TT100K\\exp2\\labels'  # YOLO格式标签路径
images_dir = 'F:\\trafficsigntest\\TT100K\\exp2\\test'  # 原始图像路径
output_dir = 'F:\\trafficsigntest\\TT100K\\exp2\\newlabels'  # 输出的Labelme JSON文件路径

# 类别映射,确保类别 ID 与 LabelImg 标签一致
class_mapping = {0:"monostyle",1:"single_cantilever",2:"gantry",3:"road_attachment",4:"double_cantilever",5:"polystyle"}

# 创建输出目录
os.makedirs(output_dir, exist_ok=True)


# 定义生成 XML 标签的函数
def create_voc_xml(image_path, image_size, shapes, output_path):
    root = ET.Element("annotation")

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

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

    path = ET.SubElement(root, "path")
    path.text = image_path

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

    size = ET.SubElement(root, "size")
    width = ET.SubElement(size, "width")
    width.text = str(image_size[0])
    height = ET.SubElement(size, "height")
    height.text = str(image_size[1])
    depth = ET.SubElement(size, "depth")
    depth.text = "3"

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

    for shape in shapes:
        obj = ET.SubElement(root, "object")
        name = ET.SubElement(obj, "name")
        name.text = shape["label"]
        pose = ET.SubElement(obj, "pose")
        pose.text = "Unspecified"
        truncated = ET.SubElement(obj, "truncated")
        truncated.text = "0"
        difficult = ET.SubElement(obj, "difficult")
        difficult.text = "0"

        bndbox = ET.SubElement(obj, "bndbox")
        xmin = ET.SubElement(bndbox, "xmin")
        xmin.text = str(int(shape["xmin"]))
        ymin = ET.SubElement(bndbox, "ymin")
        ymin.text = str(int(shape["ymin"]))
        xmax = ET.SubElement(bndbox, "xmax")
        xmax.text = str(int(shape["xmax"]))
        ymax = ET.SubElement(bndbox, "ymax")
        ymax.text = str(int(shape["ymax"]))

    # 格式化输出 XML
    xml_str = ET.tostring(root, encoding="utf-8")
    dom = parseString(xml_str)
    with open(output_path, "w") as f:
        f.write(dom.toprettyxml(indent="  "))


# 遍历 YOLO 标签文件
for label_file in os.listdir(yolo_labels_dir):
    if label_file.endswith('.txt'):
        image_file = os.path.splitext(label_file)[0] + '.jpg'
        image_path = os.path.join(images_dir, image_file)

        # 打开图像以获取其尺寸
        with Image.open(image_path) as img:
            img_width, img_height = img.size

        # 读取 YOLO 标签文件
        yolo_path = os.path.join(yolo_labels_dir, label_file)
        shapes = []

        with open(yolo_path, 'r') as f:
            for line in f.readlines():
                parts = line.strip().split()
                class_id = int(parts[0])
                x_center, y_center, width, height = map(float, parts[1:])

                # 反归一化 YOLO 坐标
                x_center *= img_width
                y_center *= img_height
                width *= img_width
                height *= img_height

                # 计算左上角和右下角的坐标
                xmin = x_center - width / 2
                ymin = y_center - height / 2
                xmax = x_center + width / 2
                ymax = y_center + height / 2

                # 添加到 shapes 列表
                shape = {
                    "label": class_mapping[class_id],
                    "xmin": xmin,
                    "ymin": ymin,
                    "xmax": xmax,
                    "ymax": ymax
                }
                shapes.append(shape)

        # 创建并保存 XML 文件
        output_path = os.path.join(output_dir, os.path.splitext(label_file)[0] + '.xml')
        create_voc_xml(image_path, (img_width, img_height), shapes, output_path)

print("转换完成!YOLO 格式数据已转换为 PASCAL VOC 格式 XML 文件。")
相关推荐
机器懒得学习2 小时前
基于YOLOv5的智能水域监测系统:从目标检测到自动报告生成
人工智能·yolo·目标检测
AI莫大猫14 小时前
(6)YOLOv4算法基本原理以及和YOLOv3 的差异
算法·yolo
KeepThinking!17 小时前
YOLO-World:Real-Time Open-Vocabulary Object Detection
人工智能·yolo·目标检测·多模态
前网易架构师-高司机20 小时前
游泳溺水识别数据集,对9984张原始图片进行YOLO,COCO JSON, VOC XML 格式的标注,平均识别率在91.7%以上
yolo·溺水·游泳溺水·游泳安全
发呆小天才O.oᯅ21 小时前
YOLOv8目标检测——详细记录使用OpenCV的DNN模块进行推理部署C++实现
c++·图像处理·人工智能·opencv·yolo·目标检测·dnn
深度学习lover1 天前
<项目代码>YOLO Visdrone航拍目标识别<目标检测>
python·yolo·目标检测·计算机视觉·visdrone航拍目标识别
深度学习lover1 天前
[项目代码] YOLOv8 遥感航拍飞机和船舶识别 [目标检测]
python·yolo·目标检测·计算机视觉·遥感航拍飞机和船舶识别
学习BigData1 天前
【使用PyQt5和YOLOv11开发电脑屏幕区域的实时分类GUI】——选择检测区域
qt·yolo·分类
红色的山茶花2 天前
YOLOv9-0.1部分代码阅读笔记-dataloaders.py
笔记·深度学习·yolo
千天夜2 天前
YOLO系列正传(三)神经网络的反向传播(back propagation)与公式推导
人工智能·python·深度学习·神经网络·学习·yolo·卷积神经网络