ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLOv8-pose托盘关键点检测:从数据集标注到抓取位姿估计

YOLOv8-pose托盘关键点检测:从数据集标注到抓取位姿估计 简介托盘关键点检测数据集面向物流自动化、工业视觉质检与机器人操作训练场景提供真实工业环境下的托盘图像与关键点标注帮助开发者构建托盘抓取定位与姿态估计模型。数据集共584张训练图与95张验证图标注为YOLO格式关键点每行包含类别ID及5组坐标点精准刻画托盘角点与支撑点等几何结构兼容主流检测框架。压缩包共1360个文件以679张jpg图像、679个txt标注文件为主另含1个yaml配置文件与1份docx说明文档整体约62.37MB目录清晰便于直接训练与验证。目前已有181人学习下载。该资源任务针对性强覆盖多样化摆放角度与光照条件可直接用于AGV、机械臂的托盘位姿估计、结构完整性检测及学术基准验证为智能仓储与工业机器人应用提供可部署的数据支撑。1. 托盘关键点检测数据集584 张训练图能撑起一个抓取定位模型吗先说结论能但前提是你得清楚它标注的是 5 个关键点而不是检测框。很多做物流自动化的兄弟一上来就想拿它训 YOLOv8 的 detect 头结果发现标签格式对不上白折腾半天。这个数据集的核心价值在于——它把托盘当成一个有姿态的刚体用 5 组坐标点刻画了托盘的几何结构直接服务于位姿估计和抓取点计算。数据集本身不大训练集 584 张验证集 95 张单类别 PalletYOLO 格式关键点标注。图片来自真实工业场景覆盖了不同摆放角度和光照条件。适合谁做 AGV 托盘对接、机械臂抓取定位、仓储视觉质检的工程师以及需要关键点检测基准数据做算法验证的研究人员。如果你手头正好有 YOLOv8-pose 的训练需求这份数据能让你在半天内跑通一个可用的托盘关键点模型。2. 拆开标注文件5 组坐标点到底怎么读、怎么转2.1 YOLO 关键点格式的字段含义YOLO 关键点标注的每一行结构是class_id x_center y_center width height px1 py1 v1 px2 py2 v2 ... px5 py5 v5。前 5 个字段是检测框后面每 3 个字段一组分别是一个关键点的 x、y 坐标和可见性标志v0 不可见v1 可见但被遮挡v2 可见且无遮挡。托盘数据集里 class_id 恒为 0因为只有 Pallet 一类。坐标全部是归一化值范围 0 到 1。这意味着你不需要关心原图分辨率直接乘上图像宽高就能还原像素坐标。但这里有个容易翻车的点不同标注工具导出的归一化基准可能不一样有的用图像绝对宽高有的用 letterbox 后的尺寸。拿到数据后第一件事就是抽几行验证一下——把归一化坐标乘回原图尺寸画在图上看看关键点是否落在托盘角点附近。2.2 用 Python 快速校验标注质量下面这段脚本我一般会先跑一遍确认标签文件和图片能对上顺便可视化几个样本看看关键点位置是否合理。import os import cv2 import numpy as np # 数据集根目录按实际路径改 DATA_ROOT pallet_keypoints IMG_DIR os.path.join(DATA_ROOT, images/train) LBL_DIR os.path.join(DATA_ROOT, labels/train) # 关键点数量托盘数据集固定为5 KPT_NUM 5 def parse_label(label_path): 解析YOLO关键点标注返回框和关键点列表 with open(label_path, r) as f: lines f.readlines() results [] for line in lines: parts line.strip().split() if len(parts) 5 KPT_NUM * 3: print(f字段数不足: {label_path}, 实际{len(parts)}) continue cls_id int(parts[0]) bbox [float(x) for x in parts[1:5]] kpts [] for i in range(KPT_NUM): base 5 i * 3 kpts.append([float(parts[base]), float(parts[base1]), int(parts[base2])]) results.append((cls_id, bbox, kpts)) return results def visualize(img_path, label_path, save_pathvis.jpg): 把关键点画到图上检查位置是否合理 img cv2.imread(img_path) h, w img.shape[:2] anns parse_label(label_path) for cls_id, bbox, kpts in anns: # 还原检测框 xc, yc, bw, bh bbox x1 int((xc - bw/2) * w) y1 int((yc - bh/2) * h) x2 int((xc bw/2) * w) y2 int((yc bh/2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) # 画关键点 for kx, ky, kv in kpts: if kv 0: px, py int(kx * w), int(ky * h) cv2.circle(img, (px, py), 4, (0, 0, 255), -1) cv2.imwrite(save_path, img) print(f已保存可视化结果: {save_path}) # 抽第一个样本跑一遍 img_files sorted(os.listdir(IMG_DIR)) if img_files: img_name img_files[0] label_name os.path.splitext(img_name)[0] .txt visualize( os.path.join(IMG_DIR, img_name), os.path.join(LBL_DIR, label_name) )这段代码的逻辑很直接读标签、解析字段、还原坐标、画图。关键参数是KPT_NUM托盘数据集固定为 5如果你拿到的标注文件字段数对不上先检查这个值。parse_label里做了字段数校验少于预期就跳过并打印警告避免后面索引越界。可视化那步建议至少抽 10 张不同角度的图看一遍确认关键点没有系统性偏移——如果所有点都往一个方向偏大概率是归一化基准搞错了。2.3 转成 YOLOv8-pose 训练格式YOLOv8-pose 对数据目录结构有固定要求images/train、images/val、labels/train、labels/val四个文件夹外加一个data.yaml描述文件。如果你拿到的压缩包已经是这个结构直接写 yaml 就能开训。如果不是按下面的方式整理。# 假设原始数据在 raw/ 下图片和标签混在一起 mkdir -p pallet_pose/images/train pallet_pose/images/val mkdir -p pallet_pose/labels/train pallet_pose/labels/val # 按文件名前缀或预先划分的列表移动文件 # 这里假设训练集和验证集已经分好直接拷贝 cp raw/train/*.jpg pallet_pose/images/train/ cp raw/train/*.txt pallet_pose/labels/train/ cp raw/val/*.jpg pallet_pose/images/val/ cp raw/val/*.txt pallet_pose/labels/val/对应的data.yaml内容path: ./pallet_pose train: images/train val: images/val kpt_shape: [5, 3] # 5个关键点每个点3个值(x,y,visible) flip_idx: [0, 1, 2, 3, 4] # 水平翻转后的关键点索引映射 names: 0: Palletkpt_shape必须和标注里的关键点数量一致写错了训练直接报错。flip_idx是数据增强时水平翻转用的托盘的关键点如果左右对称这个映射可以随便填如果关键点有明确语义顺序比如左上角、右上角翻转后索引需要对应交换否则增强会引入错误标签。托盘场景下 5 个点通常是四个角加一个中心支撑点翻转后角点顺序会变建议根据实际标注顺序调整flip_idx。3. 训练托盘关键点模型从 YOLOv8-pose 配置到首轮推理3.1 模型选型与训练参数设置YOLOv8-pose 提供了 n、s、m、l、x 五个尺度的预训练权重。托盘关键点检测属于单类别、结构固定的任务数据量不到 600 张用yolov8n-pose.pt就够了。大模型在小数据上更容易过拟合而且推理速度慢部署到 AGV 或机械臂的边缘设备上不划算。训练命令如下yolo pose train \ datapallet_pose/data.yaml \ modelyolov8n-pose.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.001 \ lrf0.01 \ patience30 \ augmentTrue \ mosaic1.0 \ degrees15 \ translate0.1 \ scale0.3 \ fliplr0.5 \ projectruns/pose \ namepallet_kpt几个参数需要根据托盘场景微调。degrees15控制随机旋转角度托盘在仓库里摆放角度多变适当旋转增强能提升泛化但别开太大超过 30 度关键点容易转出图像边界。scale0.3是随机缩放比例模拟不同距离下的托盘尺寸变化。mosaic1.0默认开启但关键点任务里 mosaic 拼接可能导致关键点归属混乱如果训练几个 epoch 后 loss 不降先把 mosaic 关掉试试。patience30是早停耐心值验证集 loss 连续 30 轮不降就停小数据集上防止过拟合。3.2 训练过程监控与指标解读训练启动后终端会输出每轮的 box_loss、pose_loss、kpt_loss 和对应的 mAP。关键点任务重点看pose_mAP50和pose_mAP50-95前者是 IoU 阈值 0.5 下的平均精度后者是 0.5 到 0.95 多阈值平均。托盘关键点如果标注准确pose_mAP50通常能到 0.9 以上如果卡在 0.6 左右上不去大概率是标注里有离群点或者关键点定义不一致。训练日志和权重默认保存在runs/pose/pallet_kpt/下weights/best.pt是验证集表现最好的权重last.pt是最后一轮的。建议用best.pt做推理除非你发现last.pt在测试集上更好——小数据集上这种情况偶尔发生因为验证集本身就有波动。3.3 推理与关键点后处理训练完之后用下面的脚本跑单张图推理把关键点画出来看看实际效果。from ultralytics import YOLO import cv2 model YOLO(runs/pose/pallet_kpt/weights/best.pt) # 推理单张图片 results model(test_pallet.jpg, conf0.5, iou0.5) for r in results: img r.plot() # 自带可视化关键点和框都画好了 cv2.imwrite(result.jpg, img) # 提取关键点坐标 if r.keypoints is not None: kpts r.keypoints.xy.cpu().numpy() # shape: (num_instances, 5, 2) confs r.keypoints.conf.cpu().numpy() # 每个点的置信度 for i, kpt in enumerate(kpts): print(f托盘{i}的关键点像素坐标:) for j, (x, y) in enumerate(kpt): print(f 点{j}: ({x:.1f}, {y:.1f}), 置信度 {confs[i][j]:.3f})conf0.5是检测框置信度阈值iou0.5是 NMS 的 IoU 阈值。关键点坐标通过r.keypoints.xy获取返回的是像素坐标直接可以用。每个点还有独立的置信度低于 0.3 的点建议丢弃说明模型对该点位置不确定。实际抓取任务里如果 5 个点里有 2 个以上置信度低于阈值这一帧的位姿估计就不可靠应该让 AGV 重新调整视角再拍一张。4. 避坑指南托盘关键点训练里最容易翻车的五件事4.1 关键点顺序不一致导致 loss 震荡现象训练前几个 epoch loss 正常下降突然某轮开始剧烈震荡pose_loss忽高忽低。原因标注文件里不同图片的关键点顺序不统一。比如有的图第一个点是左上角有的图第一个点是右下角。模型学到的映射关系自相矛盾。解决写脚本统计所有标注文件的关键点坐标分布按 xy 排序后检查顺序是否一致。不一致的样本要么重新标注要么统一重排。托盘场景下建议固定为左上、右上、右下、左下、中心。4.2 可见性标志全填 2 导致遮挡样本学偏现象模型在无遮挡托盘上表现很好但托盘被货物部分遮挡时关键点乱飞。原因标注时把所有关键点的可见性都标成了 2可见即使某些点在实际图像中被遮挡。模型没学会处理遮挡情况。解决检查标注文件里 v 值的分布。如果全是 2说明标注时没区分遮挡。对于被遮挡的点v 应该标 1 或 0。如果原始标注无法修改训练时降低遮挡样本的权重或者在数据增强里加入随机遮挡。4.3 验证集 mAP 虚高但实际推理偏移现象验证集pose_mAP50到 0.95但拿新拍的托盘图推理关键点整体偏移几十个像素。原因验证集和训练集来自同一批数据分布太接近。模型记住了训练集的特定角度和光照没学到真正的几何结构。解决从验证集里再切出一部分做测试集或者用手机在仓库里另拍几十张不同角度、不同光照的托盘图做外部验证。如果外部验证 mAP 掉到 0.7 以下说明泛化不够需要增加数据增强强度或补充训练数据。4.4 输入分辨率与标注分辨率不匹配现象训练时 imgsz 设 640但原图是 1920x1080推理时关键点坐标乘回原图尺寸后位置对不上。原因YOLO 训练时会自动 letterbox 到 imgsz关键点坐标是在 letterbox 后的图像上预测的。推理时如果直接乘原图宽高没有考虑 padding 偏移坐标就会偏。解决用r.keypoints.xy拿到的坐标已经是相对于原图的像素坐标Ultralytics 内部做了还原。如果你自己写后处理记得先减去 padding 再缩放。最稳妥的方式是直接用官方 API 输出的坐标。4.5 单类别数据里混入其他托盘类型现象模型对标准木托盘检测正常但遇到塑料托盘或金属托盘时关键点完全错位。原因数据集里只有一种托盘类型模型过拟合到了特定纹理和结构。解决如果应用场景涉及多种托盘要么补充其他类型的标注数据要么在推理时加一个托盘类型分类器做前置过滤。单类别模型不要指望它能泛化到没见过的托盘结构。5. 把关键点变成抓取位姿从像素坐标到机械臂可执行指令关键点检测的输出是 5 个像素坐标但机械臂需要的是托盘在相机坐标系下的位姿。这中间差了一个 PnP 求解。我一般会先用托盘的实际尺寸定义 3D 模型点假设托盘长 1.2m、宽 1.0m、高 0.15m5 个关键点对应 3D 坐标可以设为左上(-0.6, -0.5, 0)、右上(0.6, -0.5, 0)、右下(0.6, 0.5, 0)、左下(-0.6, 0.5, 0)、中心(0, 0, 0.15)。然后用cv2.solvePnP求解旋转和平移向量。import cv2 import numpy as np # 托盘3D模型点单位米按实际尺寸改 object_points np.array([ [-0.6, -0.5, 0.0], # 左上 [ 0.6, -0.5, 0.0], # 右上 [ 0.6, 0.5, 0.0], # 右下 [-0.6, 0.5, 0.0], # 左下 [ 0.0, 0.0, 0.15] # 中心支撑点 ], dtypenp.float32) # 相机内参需要提前标定 camera_matrix np.array([ [800, 0, 640], [0, 800, 360], [0, 0, 1] ], dtypenp.float32) dist_coeffs np.zeros(5) # 假设畸变已校正 def estimate_pose(keypoints_2d): 输入5个像素坐标返回旋转向量和平移向量 image_points np.array(keypoints_2d, dtypenp.float32) success, rvec, tvec cv2.solvePnP( object_points, image_points, camera_matrix, dist_coeffs, flagscv2.SOLVEPNP_ITERATIVE ) if not success: return None, None return rvec, tvec # 假设从YOLO推理拿到5个点 kpts_2d [(320, 240), (480, 240), (480, 400), (320, 400), (400, 320)] rvec, tvec estimate_pose(kpts_2d) if rvec is not None: print(f旋转向量: {rvec.flatten()}) print(f平移向量: {tvec.flatten()} 米)solvePnP至少需要 4 个点5 个点能提供冗余结果更稳。flags用SOLVEPNP_ITERATIVE适合点数少的情况如果点数多可以换SOLVEPNP_EPNP。平移向量的单位取决于object_points的单位这里用米输出的 tvec 就是米。实际部署时相机内参必须用棋盘格标定一次别用我上面写的默认值——那只是占位。拿到 rvec 和 tvec 之后还需要转换到机械臂基坐标系。这步涉及手眼标定不同品牌的机械臂流程不一样但核心就是求一个固定的变换矩阵。我一般会先让机械臂末端走几个已知点用cv2.calibrateHandEye算出手眼矩阵然后把相机坐标系下的托盘位姿乘上这个矩阵得到基坐标系下的抓取位姿。验证位姿估计是否准确有个简单办法把 3D 模型点用估计出的 rvec、tvec 投影回图像看投影点和检测到的关键点是否重合。重合度高说明位姿可信偏差大说明关键点检测有误或者 3D 模型尺寸不对。这个重投影误差我每次部署新场景都会跑一遍误差超过 5 个像素就停下来查原因。从那以后我每次拿到新的关键点数据集都强制走一遍「抽 10 张图可视化 → 检查关键点顺序 → 验证归一化基准 → 跑一轮小 epoch 看 loss 曲线」的流程不跳过任何一步。希望帮到你。本文还有配套的精品资源点击获取
返回列表