labelme转YOLOv8、YOLOv5 标签格式 标注数据

前言

本文分析将labelme的标签,转为YOLOv8、YOLOv5的格式,实现模型训练。

首先了解YOLOv8和YOLOv5标签格式,然后了解labelme标签格式,最近实现数据格式转换。

1、YOLOv8和YOLOv5标签格式

YOLOv8 的标签格式与 YOLOv5 基本相同,使用一种简单的txt文本格式,来存储每个图像的标注数据。

  • 每个图像对应一个文本文件,这些文本文件与图像文件位于同一目录
  • 并且具有相同的文件名,但标签文件类型是 .txt

每个文本文件包含多行,每一行代表一个物体的标注。每行包含以下信息:(相邻数据用空格间隔开)

<class_id> <x_center> <y_center> <width> <height>

  • <class_id>: 类别 ID,从 0 开始。
  • <x_center>: 边界框中心的 x 坐标,归一化到图像宽度(值在 0 到 1 之间)。
  • <y_center>: 边界框中心的 y 坐标,归一化到图像高度(值在 0 到 1 之间)。
  • <width>: 边界框的宽度,归一化到图像宽度(值在 0 到 1 之间)。
  • <height>: 边界框的高度,归一化到图像高度(值在 0 到 1 之间)。

示例:假设有一张名为 image01.jpg 的图像,其对应的标签文件 image01.txt 包含以下内容:

0 0.5 0.5 0.25 0.25
1 0.3 0.3 0.1 0.2

这表示图像中有两个对象:

  • 第一个对象的类别 ID 是 0,边界框中心点在图像的中间 (0.5, 0.5),边界框的宽度和高度分别是图像宽度和高度的 25%。
  • 第二个对象的类别 ID 是 1,边界框中心点在图像的左上方 (0.3, 0.3),边界框的宽度是图像宽度的 10%,高度是图像高度的 20%。

2、labelme标签格式

开源地址:https://github.com/labelmeai/labelme

Labelme 是一个图像标注工具,通常用于生成用于训练机器学习模型的标注数据。

Labelme 输出的数据格式是 JSON 文件,其中包含图像的标注信息。

{
    "version": "4.2.10",
    "flags": {},
    "shapes": [
        {
            "label": "class1",
            "points": [
                [x1, y1],
                [x2, y2],
                ...
            ],
            "group_id": null,
            "shape_type": "polygon",
            "flags": {}
        },
        {
            "label": "class2",
            "points": [
                [x1, y1],
                [x2, y2],
                ...
            ],
            "group_id": null,
            "shape_type": "rectangle",
            "flags": {}
        }
    ],
    "imagePath": "image_name.jpg",
    "imageData": "base64_encoded_image_data",
    "imageHeight": 1024,
    "imageWidth": 768
}
  • version: Labelme 软件的版本号。
  • flags: 一个可选的标志字典,通常为空。
  • shapes: 一个列表,包含每个标注的详细信息。
    • label: 这个标注的标签名称。
    • points: 一个数组,包含标注的点的坐标。对于多边形,每个点用 (x, y) 表示;对于矩形,通常有两个点:左上角和右下角。
    • group_id: 一个可选的组 ID,用于标记同一组的多个形状。
    • shape_type: 形状的类型,例如 "polygon"、"rectangle"、"circle" 等。
    • flags: 可选的标志字典,通常为空。
  • imagePath: 原始图像的路径或名称。
  • imageData: 图像数据的 base64 编码字符串。这个字段可以为空,如果有图像路径信息的话。
  • imageHeight: 图像的高度。
  • imageWidth: 图像的宽度。

3、labelme转YOLOv8、YOLOv5

首先定义标签名字和数字的映射 ,比如有两个类别car、bus。

label_map = {
    "car": 0,
    "bus": 1
}

如果只有单个类别,比如car。

label_map = {
    "car": 0
}

方案1——单个文件转换,代码如下所示:

import json
import os

# 定义标签映射
label_map = {
    "car": 0,
    "bus": 1
}

def convert_labelme_to_yolo(json_path, output_dir):
    with open(json_path, 'r') as f:
        labelme_data = json.load(f)

    image_width = labelme_data['imageWidth']
    image_height = labelme_data['imageHeight']

    yolo_annotations = []
    for shape in labelme_data['shapes']:
        label = shape['label']
        if label not in label_map:
            continue  # 忽略未定义的标签

        class_id = label_map[label]

        points = shape['points']
        if shape['shape_type'] == 'rectangle':
            (x1, y1), (x2, y2) = points
        elif shape['shape_type'] == 'polygon':
            x1, y1 = min(point[0] for point in points), min(point[1] for point in points)
            x2, y2 = max(point[0] for point in points), max(point[1] for point in points)
        else:
            continue  # 其他类型不处理

        x_center = (x1 + x2) / 2.0 / image_width
        y_center = (y1 + y2) / 2.0 / image_height
        width = (x2 - x1) / image_width
        height = (y2 - y1) / image_height

        yolo_annotations.append(f"{class_id} {x_center} {y_center} {width} {height}")

    output_file = os.path.join(output_dir, os.path.splitext(os.path.basename(json_path))[0] + '.txt')
    with open(output_file, 'w') as f:
        f.write('\n'.join(yolo_annotations))

# 示例使用
convert_labelme_to_yolo('/path/to/labelme_file.json', '/path/to/output_dir')

方案2——多个标签文件转换

读取一个文件下所有json文件,然后转为YOLO的txt标签格式

import json
import os

# 定义标签映射
label_map = {
    "car": 0,
    "bus": 1
}

def convert_labelme_to_yolo(json_path, output_dir):
    with open(json_path, 'r') as f:
        labelme_data = json.load(f)

    image_width = labelme_data['imageWidth']
    image_height = labelme_data['imageHeight']

    yolo_annotations = []
    for shape in labelme_data['shapes']:
        label = shape['label']
        if label not in label_map:
            continue  # 忽略未定义的标签

        class_id = label_map[label]

        points = shape['points']
        if shape['shape_type'] == 'rectangle':
            (x1, y1), (x2, y2) = points
        elif shape['shape_type'] == 'polygon':
            x1, y1 = min(point[0] for point in points), min(point[1] for point in points)
            x2, y2 = max(point[0] for point in points), max(point[1] for point in points)
        else:
            continue  # 其他类型不处理

        x_center = (x1 + x2) / 2.0 / image_width
        y_center = (y1 + y2) / 2.0 / image_height
        width = (x2 - x1) / image_width
        height = (y2 - y1) / image_height

        yolo_annotations.append(f"{class_id} {x_center} {y_center} {width} {height}")

    output_file = os.path.join(output_dir, os.path.splitext(os.path.basename(json_path))[0] + '.txt')
    with open(output_file, 'w') as f:
        f.write('\n'.join(yolo_annotations))

def process_folder(input_folder, output_folder):
    # 创建输出文件夹(如果不存在)
    os.makedirs(output_folder, exist_ok=True)
    
    # 处理输入文件夹中的每个 JSON 文件
    for filename in os.listdir(input_folder):
        if filename.endswith(".json"):
            json_path = os.path.join(input_folder, filename)
            convert_labelme_to_yolo(json_path, output_folder)

# 示例使用
input_folder = "/mnt/data/buffer_nails_all"
output_folder = "/mnt/data/yolo_labels"

process_folder(input_folder, output_folder)

# 列出输出文件夹中的文件以确认
os.listdir(output_folder)

分享完成~

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一颗小树x

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值