本文分享使用YOLO11进行目标检测时,实现模型推理预标注、自动标注、标签格式转换、以及使用Labelme手动校正标签等功能。
目录
1、预训练权重
首先我们去官网下载,YOLO11目标检测的预训练权重,如下表格式所示:
下载地址:https://github.com/ultralytics/ultralytics
Model | size (pixels) | mAPval 50-95 | Speed CPU ONNX (ms) | Speed T4 TensorRT10 (ms) | params (M) | FLOPs (B) |
---|---|---|---|---|---|---|
YOLO11n | 640 | 39.5 | 56.1 ± 0.8 | 1.5 ± 0.0 | 2.6 | 6.5 |
YOLO11s | 640 | 47.0 | 90.0 ± 1.2 | 2.5 ± 0.0 | 9.4 | 21.5 |
YOLO11m | 640 | 51.5 | 183.2 ± 2.0 | 4.7 ± 0.1 | 20.1 | 68.0 |
YOLO11l | 640 | 53.4 | 238.6 ± 1.4 | 6.2 ± 0.1 | 25.3 | 86.9 |
YOLO11x | 640 | 54.7 | 462.8 ± 6.7 | 11.3 ± 0.2 | 56.9 | 194.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博客
分享完成,欢迎大家多多点赞和收藏,谢谢~
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » YOLO11 目标检测 | 自动标注 | 预标注 | 标签格式转换 | 手动校正标签
发表评论 取消回复