本文分享使用YOLO11进行目标检测时,实现模型推理预标注自动标注标签格式转换、以及使用Labelme手动校正标签等功能。

目录

1、预训练权重

 2、生成预标注

3、分析YOLO11的目标检测格式

4、分析Labelme标注工具的格式

5、生成json标注文件

6、手动校正标签

7、Labelme的json转为YOLO的txt

8、迭代优化模型(可选)


1、预训练权重

首先我们去官网下载,YOLO11目标检测的预训练权重,如下表格式所示:

下载地址:https://github.com/ultralytics/ultralytics

Modelsize
(pixels)
mAPval
50-95
Speed
CPU ONNX
(ms)
Speed
T4 TensorRT10
(ms)
params
(M)
FLOPs
(B)
YOLO11n64039.556.1 ± 0.81.5 ± 0.02.66.5
YOLO11s64047.090.0 ± 1.22.5 ± 0.09.421.5
YOLO11m64051.5183.2 ± 2.04.7 ± 0.120.168.0
YOLO11l64053.4238.6 ± 1.46.2 ± 0.125.386.9
YOLO11x64054.7462.8 ± 6.711.3 ± 0.256.9194.9

然后基于预训练权重,准备自己的数据集,进行模型训练

最终,得到效果更好的模型权重(xxx.pt或xxx.onnx)

 2、生成预标注

前面得到了效果更好的模型权重,这里用它来对新的图片进行推理,同时生成目标检测的信息。

模型推理的代码,如下所示:

from ultralytics import YOLO
 
# 加载训练的模型
model = YOLO(r"runs/detect/train/weights/best.pt")
 
# 对指定的图像文件夹进行推理,并设置各种参数
results = model.predict(
    source="datasets/det_20241020/images/",   # 新的图片,待标注的图片
    conf=0.45,                      # 置信度阈值
    iou=0.6,                        # IoU 阈值
    imgsz=640,                      # 图像大小
    half=False,                     # 使用半精度推理
    device=None,                    # 使用设备,None 表示自动选择,比如'cpu','0'
    max_det=300,                    # 最大检测数量
    vid_stride=1,                   # 视频帧跳跃设置
    stream_buffer=False,            # 视频流缓冲
    visualize=False,                # 可视化模型特征
    augment=False,                  # 启用推理时增强
    agnostic_nms=False,             # 启用类无关的NMS
    classes=None,                   # 指定要检测的类别
    retina_masks=False,             # 使用高分辨率分割掩码
    embed=None,                     # 提取特征向量层
    show=False,                     # 是否显示推理图像
    save=True,                      # 保存推理结果
    save_frames=False,              # 保存视频的帧作为图像
    save_txt=True,                  # 保存检测结果到文本文件
    save_conf=False,                # 保存置信度到文本文件
    save_crop=False,                # 保存裁剪的检测对象图像
    show_labels=True,               # 显示检测的标签
    show_conf=True,                 # 显示检测置信度
    show_boxes=True,                # 显示检测框
    line_width=None                 # 设置边界框的线条宽度,比如2,4
)
  • 需要修改model = YOLO(r"runs/detect/train/weights/best.pt")中的权重路径,替换为自己训练的
  • 同时需要修改source="datasets/det_20241020/images/", 这里是指新的图片,即待标注的图片
  • 其他推理参数,根据任务情况,自行修改了;比如:置信度conf、iou、图像大小imgsz等等。

推理完成后,会保留目标检测的结果图像、标签信息文件夹(labels),它们是同一级文件夹的

- runs/detect/predict/

        - labels(这个文件夹是存放YOLO11推理结果,作为预标注的标签信息)

        - picture1.jpg

        - picture2.jpg

                .....

        - pictureN.jpg

3、分析YOLO11的目标检测格式

YOLO11的标签文件是一个包含每行一个标签的txt文件。

每一行的格式是:<object-class> <x_center> <y_center> <width> <height>。其中:

  • <object-class>是类别索引。
  • <x_center><y_center>是目标的中心点坐标(归一化到0-1)。
  • <width><height>是目标的宽度高度(归一化到0-1)。

txt标签示例数据,表示有两个物体:

0 0.5192 0.4512 0.3985 0.7572
3 0.5061 0.5921 0.2631 0.4561

  • 第一行表示物体1,类别为0,0.5192是中心点x坐标,0.4512是中心点y坐标,0.3985是宽度, 0.7572是高度。
  • 第二行表示物体2,类别为3,0.5061是中心点x坐标,0.5921是中心点y坐标,0.2631是宽度, 0.4561是高度。

4、分析Labelme标注工具的格式

在目标检测中,我们使用Labelme工具进行标注,选择“创建矩形”,对物体进行标注。

  • 标注后点击保存,会生成JSON标注文件;
  • 这样能使用Labelme,可视化检查预标注的结果,方便人工手动修正标签

LabelMe使用的是JSON格式,每个标签是一个形状(shape)对象,包含以下信息: 

  • label: 标签的名称。
  • points: 多边形的点列表(包含多边形顶点的坐标)。
  • group_id: (可选)用于将不同形状分组的ID。
  • shape_type: 形状类型(例如rectangle, circle等)。
  • flags: (可选)一些额外的标记信息。

5、生成json标注文件

编写程序,遍历该文件夹中的所有txt文件,然后将生成的Labelme的JSON文件保存到指定的输出文件夹中

  • 定义类别映射:创建一个字典,将YOLO11类别ID映射到相应的类名。

  • 转换函数:定义yolo_to_labelme函数,接收YOLO11格式的txt文件路径和图像尺寸,读取标注数据,计算绝对坐标,并格式化为LabelMe的JSON结构。

  • 主函数实现

    • 指定输入图像和标签文件夹路径,以及输出JSON文件的路径。
    • 检查输出目录是否存在,如不存在则创建。
    • 遍历标签文件夹中的所有.txt文件,读取相应的图像文件。
    • 使用OpenCV读取图像以获取其高度和宽度。
    • 调用转换函数生成标注数据。
    • 将生成的LabelMe格式数据写入新的JSON文件。

这里会提供源代码,需要根据我们的数据修改以下部分:

import os
import json
import cv2

# 自定义类别映射
class_map = {
    0: 'class_name1',   # 类别 0 对应的名称
    1: 'class_name2',   # 类别 1 对应的名称
    2: 'class_name3'    # 类别 2 对应的名称
}

# YOLO11的txt标签,转为Labelme的json文件
def yolo_to_labelme(txt_path, img_width, img_height):
    with open(txt_path, 'r') as file:
        lines = file.readlines()

    shapes = []
    for line in lines:
        parts = line.strip().split()
        class_id = int(parts[0])
        x_center = float(parts[1])
        y_center = float(parts[2])
        width = float(parts[3])
        height = float(parts[4])

        # 转换为绝对坐标
        x_center *= img_width
        y_center *= img_height
        width *= img_width
        height *= img_height

        # 计算矩形的四个顶点
        x1 = x_center - width / 2
        y1 = y_center - height / 2
        x2 = x_center + width / 2
        y2 = y_center + height / 2

        shapes.append({
            'label': class_map[class_id],
            'points': [[x1, y1], [x2, y2]],
            'group_id': None,
            'shape_type': 'rectangle',
            'flags': {}
        })

    return shapes

def main():
    # 文件夹路径
    image_folder_path = r"./datasets/seg-datasetsv2/images"     # 这里指定图片的文件夹路径
    txt_folder_path = r"./datasets/seg-datasetsv2/labels"       # 这里指定YOLO的txt_labels的文件夹路径
    json_output_path = r"./datasets/seg-datasetsv2/json_labels" # 这里指定待会生成Labelme的json_labels的文件夹路径

    # 检查输出文件夹是否存在,不存在则创建
    if not os.path.exists(json_output_path):
        os.makedirs(json_output_path)

    # 遍历所有txt文件并转换
    for txt_file in os.listdir(txt_folder_path):
        if txt_file.endswith('.txt'):
            txt_path = os.path.join(txt_folder_path, txt_file)

            # 获取与txt文件同名的图片路径
            img_file = txt_file.replace('.txt', '.jpg')  # 假设图片是jpg格式
            img_path = os.path.join(image_folder_path, img_file)

            try:
                # 使用OpenCV读取图片分辨率
                img = cv2.imread(img_path)
                if img is None:
                    raise FileNotFoundError(f"Image file not found: {img_path}")

                img_height, img_width, _ = img.shape

                shapes = yolo_to_labelme(txt_path, img_width, img_height)

                # 创建LabelMe格式的json文件
                labelme_data = {
                    'version': '4.5.6',
                    'flags': {},
                    'shapes': shapes,
                    'imagePath': img_file,
                    'imageData': None,
                    'imageHeight': img_height,
                    'imageWidth': img_width
                }

                json_path = os.path.join(json_output_path, txt_file.replace('.txt', '.json'))
                with open(json_path, 'w') as json_file:
                    json.dump(labelme_data, json_file, indent=2)

            except Exception as e:
                print(f"Error processing {img_file}: {e}")

# 主函数入口
if __name__ == "__main__":
    main()

 首先修改类别映射,比如:

# 定义类别标签映射
class_map = {
    0: 'person',    # 类别 0 对应的名称是person
    1: 'bicycle',   # 类别 1 对应的名称是bicycle
    2: 'car'        # 类别 2 对应的名称是car
}

然后修改一下代码中的参数:

    image_folder_path = r"./datasets/seg-datasetsv2/images"     # 这里指定图片的文件夹路径
    txt_folder_path = r"./datasets/seg-datasetsv2/labels"       # 这里指定YOLO的txt_labels的文件夹路径
    json_output_path = r"./datasets/seg-datasetsv2/json_labels" # 这里指定待会生成Labelme的json_labels的文件夹路径

运行代码,会生成用于YOLO11目标检测的JSON标签文件。

6、手动校正标签

生成了JSON文件后,把图像JSON文件放在同一个文件夹中

然后打开Labelme工具,选择“编辑多边形”,对物体进行标注信息修改

修改完成后,点击“Save"保存修正后的标注信息

7、Labelme的json转为YOLO的txt

这里把Labelme的json转为YOLO的txt,是因为用修正后数据,作为新的数据,加入旧数据中;

重新训练之前的模型权重,这样模型会学得更好,迭代优化模型。

通过下面代码,把Labelme的json转为YOLO的txt

 方案1——单个文件转换

该代码用于将LabelMe格式的JSON标注文件,转换为YOLO11格式的标注文件,函数解析:

convert_labelme_to_yolo(json_path, output_dir):

  • 功能: 将单个LabelMe格式的JSON文件转换为YOLO11格式。
  • 参数:
    • json_path (str): 输入的LabelMe格式JSON文件路径。
    • output_dir (str): 输出的YOLO11格式标注文件夹路径。
  • 操作:
    • 读取JSON文件,获取图像宽度和高度。
    • 遍历所有标注形状,提取标签和坐标,计算YOLO11所需的中心点和宽高。
    • 将结果写入以相同文件名命名的TXT文件中。

示例代码如下所示:

import json
import os

# 定义标签映射,将类别名称映射为ID
label_map = {
    "car": 0,  # 汽车
    "bus": 1   # 公交车
}

def convert_labelme_to_yolo(json_path, output_dir):
    """
    将LabelMe格式的JSON文件转换为YOLO11格式的标注文件。

    参数:
    json_path (str): 输入的LabelMe格式JSON文件路径。
    output_dir (str): 输出的YOLO11格式标注文件夹路径。
    """
    # 打开LabelMe格式的JSON文件
    with open(json_path, 'r') as f:
        labelme_data = json.load(f)  # 读取JSON数据

    # 获取图像的宽度和高度
    image_width = labelme_data['imageWidth']
    image_height = labelme_data['imageHeight']

    yolo_annotations = []  # 存储YOLO11格式的标注

    # 遍历所有的标注形状
    for shape in labelme_data['shapes']:
        label = shape['label']  # 获取标签名称
        if label not in label_map:
            continue  # 如果标签未定义,则忽略

        class_id = label_map[label]  # 获取对应的类别ID

        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  # 其他类型不处理

        # 计算YOLO11格式所需的中心点和宽高
        x_center = (x1 + x2) / 2.0 / image_width  # 计算中心点x坐标
        y_center = (y1 + y2) / 2.0 / image_height  # 计算中心点y坐标
        width = (x2 - x1) / image_width  # 计算宽度
        height = (y2 - y1) / image_height  # 计算高度

        # 添加YOLO11格式的标注到列表中
        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')
    # 将YOLO11格式的标注写入输出文件
    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文件,然后转为YOLO11的txt标签格

process_folder(input_folder, output_folder):

  • 功能: 处理输入文件夹中的所有JSON文件,转换为YOLO11格式。
  • 参数:
    • input_folder (str): 包含LabelMe格式JSON文件的输入文件夹路径。
    • output_folder (str): 用于保存YOLO11格式标注文件的输出文件夹路径。
  • 操作:
    • 创建输出文件夹(如果不存在)。
    • 遍历输入文件夹,调用转换函数处理每个以.json结尾的文件。

 示例代码如下所示:

import json
import os

# 定义标签映射,将类别名称映射为ID
label_map = {
    "car": 0,  # 汽车
    "bus": 1   # 公交车
}

def convert_labelme_to_yolo(json_path, output_dir):
    """
    将LabelMe格式的JSON文件转换为YOLO11格式的标注文件。

    参数:
    json_path (str): 输入的LabelMe格式JSON文件路径。
    output_dir (str): 输出的YOLO11格式标注文件夹路径。
    """
    # 打开LabelMe格式的JSON文件
    with open(json_path, 'r') as f:
        labelme_data = json.load(f)  # 读取JSON数据

    # 获取图像的宽度和高度
    image_width = labelme_data['imageWidth']
    image_height = labelme_data['imageHeight']

    yolo_annotations = []  # 存储YOLO11格式的标注

    # 遍历所有的标注形状
    for shape in labelme_data['shapes']:
        label = shape['label']  # 获取标签名称
        if label not in label_map:
            continue  # 如果标签未定义,则忽略

        class_id = label_map[label]  # 获取对应的类别ID

        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  # 其他类型不处理

        # 计算YOLO11格式所需的中心点和宽高
        x_center = (x1 + x2) / 2.0 / image_width  # 计算中心点x坐标
        y_center = (y1 + y2) / 2.0 / image_height  # 计算中心点y坐标
        width = (x2 - x1) / image_width  # 计算宽度
        height = (y2 - y1) / image_height  # 计算高度

        # 添加YOLO11格式的标注到列表中
        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')
    # 将YOLO11格式的标注写入输出文件
    with open(output_file, 'w') as f:
        f.write('\n'.join(yolo_annotations))

def process_folder(input_folder, output_folder):
    """
    处理输入文件夹中的所有JSON文件,并将其转换为YOLO11格式的标注文件。

    参数:
    input_folder (str): 输入文件夹路径,包含LabelMe格式的JSON文件。
    output_folder (str): 输出文件夹路径,用于保存YOLO11格式的标注文件。
    """
    # 创建输出文件夹(如果不存在)
    os.makedirs(output_folder, exist_ok=True)
    
    # 处理输入文件夹中的每个 JSON 文件
    for filename in os.listdir(input_folder):
        if filename.endswith(".json"):  # 只处理以 .json 结尾的文件
            json_path = os.path.join(input_folder, filename)  # 获取完整的JSON文件路径
            convert_labelme_to_yolo(json_path, output_folder)  # 调用转换函数

# 示例使用
input_folder = "/mnt/data/json_labels"  # 输入json_labels文件夹路径
output_folder = "/mnt/data/yolo11_txt_labels"  # 输出txt_labels文件夹路径

process_folder(input_folder, output_folder)  # 处理文件夹中的所有JSON文件

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

我们使用上面代码时,需要设置输入的json_labels文件夹路径输出txt_labels文件夹路径

input_folder = "/mnt/data/json_labels"  # 输入json_labels文件夹路径
output_folder = "/mnt/data/yolo11_txt_labels"  # 输出txt_labels文件夹路径

8、迭代优化模型(可选)

然后,可以迭代优化模型。用修正后数据,作为新的数据,加入旧数据中;

重新训练之前的模型权重,这样模型会学得更好,迭代优化模型。

YOLO11目标检测-训练模型参考我这篇文章:

https://blog.csdn.net/qq_41204464/article/details/142826049?spm=1001.2014.3001.5501

  YOLO11相关文章推荐:

一篇文章快速认识YOLO11 | 关键改进点 | 安装使用 | 模型训练和推理-CSDN博客

一篇文章快速认识 YOLO11 | 实例分割 | 模型训练 | 自定义数据集-CSDN博客

YOLO11模型推理 | 目标检测与跟踪 | 实例分割 | 关键点估计 | OBB旋转目标检测-CSDN博客

YOLO11模型训练 | 目标检测与跟踪 | 实例分割 | 关键点姿态估计-CSDN博客

YOLO11 实例分割 | 自动标注 | 预标注 | 标签格式转换 | 手动校正标签-CSDN博客

YOLO11 实例分割 | 导出ONNX模型 | ONNX模型推理-CSDN博客

YOLO11 目标检测 | 导出ONNX模型 | ONNX模型推理-CSDN博客

分享完成,欢迎大家多多点赞收藏,谢谢~

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部