Windows10下YOLOv8-Pose实战:从Labelme标注到自定义数据集训练全流程

发布时间:2026/5/27 12:38:16

Windows10下YOLOv8-Pose实战:从Labelme标注到自定义数据集训练全流程 1. 数据标注与处理在Windows10环境下使用YOLOv8-Pose进行关键点检测数据标注是第一步也是最重要的一步。我推荐使用Labelme这个开源工具它支持矩形框和关键点的标注而且操作简单直观。1.1 使用Labelme标注数据安装Labelme非常简单直接使用pip命令即可pip install labelme标注时有个小技巧先标注所有图片的矩形框再统一标注关键点。具体操作时建议按关键点类别分批标注比如先标注所有左眼关键点再标注右眼最后标注鼻子。这样做有两个好处标注效率更高不需要频繁切换关键点类别减少标注错误避免混淆不同类别的关键点标注完成后每张图片会生成对应的JSON文件里面包含了所有标注信息。我建议在标注过程中定期保存避免意外丢失数据。1.2 数据可视化检查标注完成后一定要做可视化检查这是很多新手容易忽略的步骤。下面这段Python代码可以帮助你快速检查标注质量import os import cv2 import json def visualize_annotations(image_folder): for filename in os.listdir(image_folder): if filename.endswith(.jpg): img_path os.path.join(image_folder, filename) json_path os.path.join(image_folder, filename.replace(.jpg, .json)) img cv2.imread(img_path) with open(json_path, r) as f: data json.load(f) # 绘制矩形框 for shape in data[shapes]: if shape[shape_type] rectangle: points shape[points] cv2.rectangle(img, (int(points[0][0]), int(points[0][1])), (int(points[1][0]), int(points[1][1])), (0, 255, 0), 2) # 绘制关键点 elif shape[shape_type] point: point shape[points][0] cv2.circle(img, (int(point[0]), int(point[1])), 5, (0, 0, 255), -1) cv2.imshow(Annotation Check, img) if cv2.waitKey(0) 0xFF ord(q): break visualize_annotations(your_image_folder)运行这段代码后你可以通过按空格键查看下一张图片按Q键退出。检查时主要关注矩形框是否准确包围目标关键点位置是否正确是否有漏标或错标的情况2. 数据预处理2.1 数据集组织良好的数据组织是训练成功的基础。我建议采用如下目录结构dataset/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/可以使用以下代码将图片和JSON标签文件分开存放import os import shutil def organize_files(source_dir, img_dest, json_dest): os.makedirs(img_dest, exist_okTrue) os.makedirs(json_dest, exist_okTrue) for file in os.listdir(source_dir): src_path os.path.join(source_dir, file) if file.endswith(.jpg): shutil.move(src_path, os.path.join(img_dest, file)) elif file.endswith(.json): shutil.move(src_path, os.path.join(json_dest, file))2.2 数据集划分数据集通常需要划分为训练集和验证集比例一般为8:2。下面是一个自动划分数据集的脚本import os import random from tqdm import tqdm def split_dataset(image_dir, json_dir, val_ratio0.2): all_images [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.shuffle(all_images) val_size int(len(all_images) * val_ratio) val_images all_images[:val_size] train_images all_images[val_size:] # 创建子目录 os.makedirs(os.path.join(image_dir, train), exist_okTrue) os.makedirs(os.path.join(image_dir, val), exist_okTrue) os.makedirs(os.path.join(json_dir, train), exist_okTrue) os.makedirs(os.path.join(json_dir, val), exist_okTrue) # 移动文件 for img in tqdm(train_images): json_file img.replace(.jpg, .json) shutil.move(os.path.join(image_dir, img), os.path.join(image_dir, train, img)) shutil.move(os.path.join(json_dir, json_file), os.path.join(json_dir, train, json_file)) for img in tqdm(val_images): json_file img.replace(.jpg, .json) shutil.move(os.path.join(image_dir, img), os.path.join(image_dir, val, img)) shutil.move(os.path.join(json_dir, json_file), os.path.join(json_dir, val, json_file))3. 格式转换YOLOv8-Pose需要特定的标签格式我们需要将Labelme的JSON格式转换为YOLO的TXT格式。3.1 理解YOLO格式YOLO格式的每一行代表一个对象包含类别ID边界框中心坐标(x,y)和宽高(w,h)都是归一化后的值关键点信息每组包含x,y,visibility(0不可见,1遮挡,2可见)例如0 0.5 0.5 0.3 0.4 0.4 0.6 2 0.6 0.4 2 0.5 0.7 23.2 转换代码实现下面是完整的转换代码import json import os from tqdm import tqdm def json_to_yolo(json_dir, output_dir, class_map, keypoint_classes): os.makedirs(output_dir, exist_okTrue) for json_file in tqdm(os.listdir(json_dir)): if not json_file.endswith(.json): continue with open(os.path.join(json_dir, json_file), r) as f: data json.load(f) img_width data[imageWidth] img_height data[imageHeight] output_lines [] for shape in data[shapes]: if shape[shape_type] rectangle: # 处理边界框 points shape[points] x_min min(p[0] for p in points) x_max max(p[0] for p in points) y_min min(p[1] for p in points) y_max max(p[1] for p in points) # 计算归一化值 x_center ((x_min x_max) / 2) / img_width y_center ((y_min y_max) / 2) / img_height width (x_max - x_min) / img_width height (y_max - y_min) / img_height # 获取类别ID class_id class_map.get(shape[label], 0) line f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f} # 收集该框内的关键点 kpts_in_box {} for kpt_shape in data[shapes]: if kpt_shape[shape_type] point: kpt_x, kpt_y kpt_shape[points][0] if x_min kpt_x x_max and y_min kpt_y y_max: kpts_in_box[kpt_shape[label]] (kpt_x, kpt_y) # 按预定顺序添加关键点 for kpt_class in keypoint_classes: if kpt_class in kpts_in_box: kpt_x, kpt_y kpts_in_box[kpt_class] line f {kpt_x/img_width:.6f} {kpt_y/img_height:.6f} 2 else: line 0 0 0 output_lines.append(line) # 写入TXT文件 output_file os.path.join(output_dir, json_file.replace(.json, .txt)) with open(output_file, w) as f: f.write(\n.join(output_lines)) # 使用示例 class_map {person: 0} # 类别映射 keypoint_classes [left_eye, right_eye, nose] # 关键点类别顺序 json_to_yolo(label_json/train, labels/train, class_map, keypoint_classes) json_to_yolo(label_json/val, labels/val, class_map, keypoint_classes)4. 模型训练4.1 环境配置首先需要配置Python环境建议使用condaconda create -n yolo8 python3.8 conda activate yolo8安装PyTorch根据你的CUDA版本选择pip install torch1.12.1cu116 torchvision0.13.1cu116 torchaudio0.12.1 --extra-index-url https://download.pytorch.org/whl/cu116安装Ultralytics包pip install ultralytics4.2 准备配置文件创建一个YAML配置文件如pose_data.yaml内容如下# 数据集路径 path: ./dataset train: images/train val: images/val # 关键点配置 kpt_shape: [3, 2] # 3个关键点每个点有x,y坐标 flip_idx: [1, 0, 2] # 水平翻转时关键点的对应关系 # 类别 names: 0: person4.3 开始训练使用以下命令开始训练yolo pose train datapose_data.yaml modelyolov8n-pose.pt epochs100 imgsz640 batch16 device0关键参数说明model: 选择基础模型如yolov8n-pose(小)、yolov8s-pose(中)、yolov8m-pose(大)epochs: 训练轮次imgsz: 输入图像尺寸batch: 批大小根据GPU内存调整device: 使用GPU(0)或CPU4.4 训练技巧学习率调整如果损失不下降可以尝试减小学习率yolo pose train ... lr00.01 lrf0.01数据增强默认开启马赛克增强对小数据集特别有效早停机制设置patience参数当验证集指标不再提升时自动停止训练恢复训练如果训练中断可以从中断点继续yolo pose train ... resumeTrue5. 模型使用与部署5.1 模型验证训练完成后使用以下命令评估模型性能yolo pose val modelpath/to/best.pt datapose_data.yaml5.2 模型预测5.2.1 图片预测from ultralytics import YOLO model YOLO(path/to/best.pt) results model(test_image.jpg, saveTrue)5.2.2 视频预测from ultralytics import YOLO model YOLO(path/to/best.pt) results model.predict(sourceinput_video.mp4, showTrue, saveTrue, conf0.5)5.2.3 实时摄像头import cv2 from ultralytics import YOLO model YOLO(path/to/best.pt) cap cv2.VideoCapture(0) while cap.isOpened(): ret, frame cap.read() if not ret: break results model(frame, showTrue) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()5.3 自定义可视化如果你想自定义关键点显示效果可以使用以下代码def draw_keypoints(image, results, kpt_colors, skeleton): for result in results: for kpts in result.keypoints.xy: # 绘制关键点 for i, (x, y) in enumerate(kpts): color kpt_colors[i] cv2.circle(image, (int(x), int(y)), 5, color, -1) # 绘制骨架连线 for (start, end) in skeleton: x1, y1 kpts[start-1] x2, y2 kpts[end-1] cv2.line(image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) return image # 使用示例 kpt_colors [(255,0,0), (0,255,0), (0,0,255)] # 每个关键点的颜色 skeleton [(1,2), (2,3)] # 关键点连接关系 annotated_img draw_keypoints(original_img, results, kpt_colors, skeleton)6. 常见问题解决在实际项目中我遇到过不少坑这里分享几个常见问题的解决方法CUDA内存不足减小batch_size减小imgsz(输入图像尺寸)使用更小的模型(yolov8n-pose)关键点预测不准确检查标注质量确保关键点位置精确增加训练数据量调整pose和kobj损失权重模型过拟合增加数据增强使用早停机制添加正则化训练速度慢使用更强大的GPU减小imgsz使用混合精度训练(ampTrue)评估指标异常检查数据集划分是否正确确保验证集和训练集分布一致检查标签文件是否正确7. 性能优化技巧经过多次项目实践我总结出几个提升YOLOv8-Pose性能的技巧数据层面确保标注质量是关键特别是关键点位置要精确数据增强要适度过多的增强可能影响模型学习类别平衡很重要避免某些关键点样本过少模型层面小数据集建议使用预训练权重(pretrainedTrue)根据需求选择合适的模型大小不是越大越好可以尝试调整损失函数权重训练技巧使用学习率warmup尝试不同的优化器(Adam/SGD)适当调整马赛克增强的概率推理优化使用TensorRT加速量化模型减小体积调整置信度阈值平衡精度和召回率8. 实际应用案例以一个工业质检项目为例我们需要检测电路板上的特定组件并定位其关键点。整个流程如下收集约500张电路板图像使用Labelme标注组件边界框和3个定位孔作为关键点训练yolov8s-pose模型迭代100个epoch部署到生产线进行实时检测关键配置# 电路板检测配置 kpt_shape: [3, 2] # 3个定位孔 flip_idx: [] # 不需要水平翻转训练命令yolo pose train datacircuit.yaml modelyolov8s-pose.pt epochs100 imgsz640 batch8 device0 pose12.0 kobj1.5最终模型在验证集上达到mAP0.5: 0.92关键点误差2像素推理速度45FPS(在RTX 3060上)

相关新闻