YOLOv8-Pose训练数据准备避坑指南:从Labelme标注到txt格式的完整流程与可视化校验
YOLOv8-Pose训练数据准备全流程从Labelme标注到可视化校验的避坑实践在计算机视觉领域姿态估计任务对数据格式的要求往往比普通目标检测更加复杂。许多开发者在准备YOLOv8-Pose训练数据时容易在格式转换环节踩坑——可能是关键点顺序错乱或是可见性标志缺失最终导致模型无法正常收敛。本文将分享一套经过实战检验的数据预处理方案重点解析从Labelme标注到YOLOv8-Pose标准格式的完整转换逻辑以及每个环节必须注意的验证要点。1. 理解YOLOv8-Pose的数据格式规范YOLOv8-Pose的标注文件采用纯文本格式每行对应一个实例的完整描述。与常规目标检测不同姿态估计需要额外处理17个关键点的坐标和可见性状态。典型的一行数据如下0 0.512 0.634 0.223 0.356 0.529 0.712 2 0.501 0.689 2 ... 后续14个关键点各字段含义解析前5个值类别索引、边界框中心x、中心y、宽度、高度均归一化到0-1范围后续51个值17个关键点的[x,y,visibility]三元组其中visibility取值为0未标注1标注但不可见遮挡2标注且可见关键点顺序必须严格遵循COCO标准鼻子左眼右眼左耳右耳左肩右肩左肘右肘左腕右腕左髋右髋左膝右膝左踝右踝2. Labelme到COCO格式的转换策略Labelme的原始JSON标注与目标格式存在三个主要差异关键点使用自由标签而非固定索引边界框可能缺失或采用不同表示法组标识group_id需要特殊处理关键转换代码解析labelme2coco.pyclass Lableme2CoCo: def __init__(self, splitDir): self.splitDir splitDir # 路径截断标识符 def to_coco(self, json_path_list): for json_path in json_path_list: obj self.read_jsonfile(json_path) shapes obj[shapes] # 按group_id分组处理多人物实例 groupIds [shape[group_id] for shape in shapes] for groupId in set(groupIds): keyPoints [0] * 51 # 初始化17*351维关键点数组 bbox [] for shape in shapes: if shape[group_id] ! groupId: continue if shape[shape_type] point: labelNum int(shape[label]) # 关键点编号 # 坐标取整并设置可见性为2 keyPoints[labelNum*3] int(shape[points][0][0]0.5) keyPoints[labelNum*31] int(shape[points][0][1]0.5) keyPoints[labelNum*32] 2 elif shape[shape_type] rectangle: x0, y0, x1, y1 shape[points][0][0], shape[points][0][1], \ shape[points][1][0], shape[points][1][1] bbox [min(x0,x1), min(y0,y1), max(x0,x1)-min(x0,x1), max(y0,y1)-min(y0,y1)] if sum(keyPoints[2::3]) 0: # 至少有一个有效关键点 annotation self._annotation(bbox, keyPoints, sum(1 for x in keyPoints[2::3] if x2)) self.annotations.append(annotation)关键参数说明splitDir用于从完整路径中提取相对路径的截断标识。例如设置splitDirlabelMePoint\\时路径G:\data\labelMePoint\images\1.jpg将保存为images/1.jpg常见问题解决方案关键点编号冲突确保Labelme中点的标签为0-16的整数路径不一致检查splitDir是否与实际存储结构匹配多人场景处理依赖group_id正确分组标注时需确保同一人物的所有关键点和边界框具有相同group_id3. COCO到YOLOv8-Pose格式的终极转换获得COCO格式JSON后需要使用slefjson2posetxt.py进行最终转换def convert_coco_json(cocojsonpath, savepath, use_keypointsTrue): for json_file in Path(cocojsonpath).glob(*.json): with open(json_file) as f: data json.load(f) images {f{x[id]:d}: x for x in data[images]} imgToAnns defaultdict(list) for ann in data[annotations]: imgToAnns[ann[image_id]].append(ann) for img_id, anns in imgToAnns.items(): img images[f{img_id:d}] h, w img[height], img[width] for ann in anns: if use_keypoints and ann.get(keypoints): kpts np.array(ann[keypoints]).reshape(-1, 3) kpts kpts / np.array([w, h, 1]) # 归一化 with open(f{savepath}/{img[file_name].replace(.jpg,.txt)}, a) as f: f.write((%g *(451)).rstrip() % ( ann[category_id]-1, # class (ann[bbox][0]ann[bbox][2]/2)/w, # cx (ann[bbox][1]ann[bbox][3]/2)/h, # cy ann[bbox][2]/w, # width ann[bbox][3]/h, # height *kpts.reshape(-1).tolist() # 17*3 keypoints ) \n)转换过程中的典型陷阱坐标未归一化必须将绝对坐标转换为相对坐标关键点可见性丢失确保第三维的visibility标志被保留文件路径错误注意Windows与Linux路径分隔符差异4. 可视化校验避免前功尽弃的关键步骤完成格式转换后必须通过可视化确认标注准确性。PoseVisualization.py脚本的核心逻辑def visualize_pose(img_path, txt_path): img cv2.imread(img_path) h, w img.shape[:2] with open(txt_path) as f: for line in f.readlines(): data list(map(float, line.strip().split())) # 绘制边界框 cx, cy, bw, bh data[1]*w, data[2]*h, data[3]*w, data[4]*h cv2.rectangle(img, (int(cx-bw/2), int(cy-bh/2)), (int(cxbw/2), int(cybh/2)), (0,255,0), 2) # 绘制关键点 kpts [] for i in range(17): x, y, s data[5i*3], data[6i*3], data[7i*3] if s 0: cv2.circle(img, (int(x*w), int(y*h)), 5, COLORS[i], -1) kpts.append([int(x*w), int(y*h), int(s)]) # 绘制骨骼连线 for (start, end) in SKELETON: # COCO定义的17点连接关系 if kpts[start-1][2] 0 and kpts[end-1][2] 0: cv2.line(img, tuple(kpts[start-1][:2]), tuple(kpts[end-1][:2]), (255,0,0), 2) cv2.imshow(Preview, cv2.resize(img, (0,0), fx0.7, fy0.7)) cv2.waitKey(0)验证时需特别关注关键点与人体部位的对应关系是否正确被遮挡关键点的visibility标志是否为1边界框是否合理包裹整个人体多人场景下实例是否区分正确5. 数据整理与路径处理最后使用pickImg.py将图片文件整理到对应目录def organize_images(img_dir, txt_dir, output_dir): os.makedirs(output_dir, exist_okTrue) txt_files {os.path.basename(f).replace(.txt, ) for f in glob.glob(f{txt_dir}/*.txt)} for img_file in glob.glob(f{img_dir}/*.jpg): base_name os.path.basename(img_file).replace(.jpg, ) if base_name in txt_files: shutil.copy(img_file, f{output_dir}/{base_name}.jpg)目录结构建议dataset/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/实际项目中遇到的典型问题图像与标注文件命名不一致验证集缺少对应标注路径中包含中文或特殊字符这套流程已在多个工业级姿态估计项目中验证包括生产线工人动作分析和体育训练监测系统。关键是要建立标准化的标注规范并在每个转换环节后进行可视化抽查。特别是在多人密集场景中group_id的正确使用和关键点顺序的严格校验尤为重要。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2591885.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!