ARTICLE DETAIL

资讯详情

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

160张图跑实例分割:包裹与条码YOLO数据集实战

160张图跑实例分割:包裹与条码YOLO数据集实战 简介这份包裹与条码实例分割数据集面向物流自动化、智能仓储与计算机视觉方向的研究者及算法工程师用于训练模型精确识别包裹与条码轮廓解决分拣流水线中目标定位与计数问题。资源共322个文件以160张JPEG实景图片和160个YOLO格式TXT标注文件为主另含1个yaml配置与1份docx说明文档压缩包约13.97MB标注采用多边形坐标点可直接接入YOLO等主流框架训练。数据集划分训练集147张、验证集6张、测试集7张涵盖barcode、package、packages三类覆盖单包裹、多包裹堆叠及条码标签等物流核心场景。已有207人学习下载。读者可据此快速搭建实例分割实验基线省去标注与预处理成本并借助真实场景数据验证模型在自动化分拣、库存盘点、异常监控等任务中的泛化能力适合作为算法创新与工程落地的基准数据。1. 160 张图也能跑实例分割包裹与条码数据集到底能解决什么物流分拣线上最让人头疼的不是包裹多而是包裹和条码贴在一起、堆叠在一起检测框一画就把两个目标框进同一个矩形里。矩形框只能告诉你「这里有个东西」但分拣机械臂需要知道「包裹的轮廓在哪、条码贴在包裹的哪个面」。这就是实例分割和普通目标检测的分水岭。这份包裹与条码实例分割数据集总共 160 张真实场景 JPEG 图片训练集 147 张、验证集 6 张、测试集 7 张标注格式是 YOLO 的多边形坐标 TXT类别只有三个barcode、package、packages。它适合谁适合手头有 YOLOv8-seg 或类似实例分割框架、想快速验证物流场景分割效果、又不想从零标数据的开发者。160 张不算多但胜在标注是真实轮廓而非矩形近似拿来跑通流程、验证类别定义、做小样本微调够用。2. YOLO 多边形标注怎么读从 TXT 到 mask 的完整链路2.1 为什么是 YOLO-seg 格式而不是 COCO JSON拿到数据集第一件事是确认标注格式。这份数据用的是 YOLO 分割格式每张图对应一个同名 TXT每行一个实例结构是class_id x1 y1 x2 y2 ... xn yn所有坐标都是归一化到 0~1 的相对值不是像素值。这一点和 COCO 的 polygon 标注逻辑一致但 COCO 用 JSON 嵌套结构存YOLO 用纯文本平铺。选 YOLO 格式的好处是加载快、解析简单、和 ultralytics 生态无缝对接代价是类别名和类别 ID 的映射关系不在标注文件里得靠一个额外的data.yaml来维护。三个类别的 ID 映射常见做法是类别名建议 ID含义barcode0条码标签区域package1单个包裹轮廓packages2多个包裹的集合区域这里有个容易翻车的点package和packages在语义上有重叠。一张图里如果既有单个包裹又有一堆包裹标注者可能把同一个物理对象既标成 package 又标成 packages。训练前建议先抽查几十张图的标注确认这两个类别的边界是否清晰。如果发现大量重叠标注要么合并类别要么在训练时用类别权重压制。2.2 用 Python 解析标注并可视化验证在正式训练前我一般会写一段脚本把标注画回原图肉眼确认多边形有没有偏移、有没有越界。这一步能提前暴露归一化坐标算错、图片和 TXT 不对应等问题。import cv2 import numpy as np import os # 类别颜色映射BGR COLORS {0: (0, 0, 255), 1: (0, 255, 0), 2: (255, 0, 0)} NAMES {0: barcode, 1: package, 2: packages} def draw_yolo_seg(img_path, txt_path, save_path): img cv2.imread(img_path) h, w img.shape[:2] if not os.path.exists(txt_path): print(f缺失标注: {txt_path}) return with open(txt_path, r) as f: lines f.readlines() for line in lines: parts line.strip().split() if len(parts) 7: # 至少 3 个点才构成多边形 continue cls_id int(parts[0]) coords np.array(list(map(float, parts[1:]))).reshape(-1, 2) # 反归一化到像素坐标 coords[:, 0] * w coords[:, 1] * h pts coords.astype(np.int32).reshape((-1, 1, 2)) cv2.polylines(img, [pts], isClosedTrue, colorCOLORS.get(cls_id, (255, 255, 255)), thickness2) # 在第一个点旁边写类别名 cv2.putText(img, NAMES.get(cls_id, str(cls_id)), tuple(pts[0][0]), cv2.FONT_HERSHEY_SIMPLEX, 0.6, COLORS.get(cls_id, (255, 255, 255)), 2) cv2.imwrite(save_path, img) # 批量跑一遍训练集 img_dir images/train txt_dir labels/train out_dir vis_train os.makedirs(out_dir, exist_okTrue) for name in os.listdir(img_dir): if name.lower().endswith((.jpg, .jpeg, .png)): stem os.path.splitext(name)[0] draw_yolo_seg(os.path.join(img_dir, name), os.path.join(txt_dir, stem .txt), os.path.join(out_dir, name))这段代码的逻辑很直白读图、读 TXT、把归一化坐标乘回宽高、用polylines画闭合多边形。参数上注意thickness2在 160 张图这种小规模下够用如果图片分辨率很高可以加到 3。跑完之后重点看三件事多边形是否贴合包裹边缘、条码区域是否被单独框出、有没有坐标全为 0 或超出 1 的异常行。我遇到过标注文件里混入空行导致解析报错的情况所以len(parts) 7这个判断不能省。2.3 目录结构怎么组织才能被 ultralytics 直接吃进去ultralytics 对目录结构有约定不按它的来就得改配置。推荐这样摆dataset/ ├── images/ │ ├── train/ (147 张) │ ├── val/ (6 张) │ └── test/ (7 张) ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamldata.yaml内容path: ./dataset train: images/train val: images/val test: images/test nc: 3 names: 0: barcode 1: package 2: packages注意path用相对路径时训练命令的工作目录要和它对齐否则会报「找不到图片」。验证集只有 6 张这个数量在训练中只能起到「不崩」的监控作用不能用来做模型选择。真正评估要看测试集那 7 张或者自己再切一部分训练集出来。3. 用 YOLOv8-seg 跑通训练参数怎么设、指标怎么看3.1 从预训练权重出发的小样本微调策略160 张图直接从头训实例分割基本等于随机初始化收敛慢且容易过拟合。常见做法是加载yolov8n-seg.pt或yolov8s-seg.pt做微调。n 版参数量小适合这种小数据集快速验证s 版精度略高但需要更多显存。我一般先用 n 版跑一轮看 loss 曲线确认标注没问题再换 s 版。训练命令yolo segment train \ datadataset/data.yaml \ modelyolov8n-seg.pt \ epochs100 \ imgsz640 \ batch8 \ lr00.001 \ patience20 \ projectruns/seg \ namepackage_barcode_v1参数逐个说epochs100对小数据集偏多配合patience20早停能防止无效训练imgsz640是 YOLO 系列的默认输入尺寸如果你的原图分辨率远大于 640包裹上的条码可能被缩到几个像素这时候要考虑切图或提高imgszbatch8在单卡 8G 显存下比较稳显存够可以加到 16lr00.001是微调的常用起点比从头训练的 0.01 低一个量级。3.2 分割指标 mask mAP 和 box mAP 的差异解读训练日志里会同时出现 box loss 和 seg loss验证指标有metrics/mAP50(B)和metrics/mAP50(M)B 是 boxM 是 mask。这两个指标的差距能反映标注质量如果 box mAP 高但 mask mAP 低很多说明多边形轮廓标得不够准或者模型没学好边界。在包裹场景里条码区域通常很小mask 指标对条码类会明显低于包裹类这是正常的不要一看到条码 mAP 低就以为训练失败。验证命令yolo segment val \ modelruns/seg/package_barcode_v1/weights/best.pt \ datadataset/data.yaml \ splittest \ imgsz640splittest会跑那 7 张测试图。输出里每个类别的Mask-P、Mask-R、Mask-mAP50都要看。如果packages类的召回率特别低大概率是训练集里这个类别的实例数太少可以考虑对包含 packages 的图片做过采样或者用 mosaic 增强提升小类别出现频率。3.3 推理与结果导出把 mask 叠回原图训练完最直观的验证是拿几张图跑推理看 mask 叠上去的效果。from ultralytics import YOLO model YOLO(runs/seg/package_barcode_v1/weights/best.pt) results model.predict( sourcedataset/images/test, imgsz640, conf0.25, iou0.5, saveTrue, projectruns/predict, nametest_vis ) # 逐张打印检测到的类别和置信度 for r in results: boxes r.boxes masks r.masks if boxes is None: print(f{r.path}: 无检测结果) continue for i in range(len(boxes)): cls_id int(boxes.cls[i]) conf float(boxes.conf[i]) print(f{r.path} - class{model.names[cls_id]}, conf{conf:.3f})conf0.25是默认阈值条码这种小目标可以降到 0.15 试试但会引入更多误检。iou0.5控制 NMS 的合并力度包裹堆叠场景下如果两个包裹挨得很近iou 设太高会把它们合并成一个设太低又会重复检测0.5 是个折中起点。saveTrue会把带 mask 的可视化图存到runs/predict/test_vis直接打开看效果。4. 避坑与排查小数据集训练实例分割的五个血泪经验4.1 验证集只有 6 张指标波动大到没法看现象每跑一个 epoch验证集的 mask mAP 上下跳十几个点完全看不出收敛趋势。原因6 张图的验证集样本量太小一张图预测好坏就能把整体指标拉高或拉低统计意义几乎为零。解决把训练集里再切 20~30 张出来做验证或者用 K 折交叉验证。如果坚持用原验证集就只看 loss 曲线是否平稳下降不要盯 mAP 的绝对值。4.2 package 和 packages 类别混淆导致 mask 重叠现象推理结果里同一个包裹区域同时出现 package 和 packages 两个 mask颜色叠在一起。原因标注阶段两个类别的定义边界模糊训练时模型学到的特征区分度不够。解决先统计训练集中两个类别的实例数量比例如果 packages 实例远少于 package考虑合并为一个类别或者对 packages 做单独的数据增强。也可以在 loss 里给 packages 更高的类别权重。4.3 条码区域太小mask 几乎不可见现象训练日志里 barcode 类的 mask mAP 长期在 0.1 以下推理图上条码 mask 只有几个像素。原因条码在原图中占比很小缩放到 640 后信息进一步丢失分割头难以学到有效边界。解决提高输入尺寸到 1024 或 1280或者对包含条码的区域做裁剪增强。另一个思路是把条码检测退化为关键点检测但这就偏离了实例分割的任务定义。4.4 标注文件里的多边形点序混乱导致 mask 自交叉现象可视化时某些 mask 出现奇怪的蝴蝶结形状面积计算异常。原因标注时点的顺序没有按顺时针或逆时针排列多边形边自交叉。解决在数据加载阶段加一个检查用cv2.contourArea计算多边形面积如果面积接近 0 或异常大就标记出来人工修正。也可以在解析时用cv2.convexHull强制转凸包但会损失轮廓精度慎用。4.5 训练 loss 下降但推理效果差怀疑过拟合现象训练集 loss 降到很低但测试集推理时漏检严重。原因160 张图对实例分割来说偏少模型记住了训练样本的纹理而非通用特征。解决加大数据增强力度特别是 mosaic、mixup 和随机缩放。YOLOv8 默认开启 mosaic可以额外加degrees10、translate0.1、scale0.5。另外把dropout调高如果模型支持或者用更小的模型容量。5. 把 160 张图用出 1600 张的效果增强策略与迁移验证小数据集做实例分割核心矛盾是标注成本高、样本多样性不足。160 张图如果直接训模型很容易过拟合到背景纹理。我的习惯是在训练前先做一轮离线增强把训练集扩到 3~5 倍再配合在线增强。离线增强用 albumentations 比较顺手import albumentations as A import cv2 import os import numpy as np transform A.Compose([ A.HorizontalFlip(p0.5), A.RandomBrightnessContrast(p0.3), A.ShiftScaleRotate(shift_limit0.05, scale_limit0.2, rotate_limit15, p0.5), A.MotionBlur(blur_limit5, p0.2), A.CLAHE(p0.2), ], bbox_paramsNone) img_dir dataset/images/train txt_dir dataset/labels/train out_img dataset/images/train_aug out_txt dataset/labels/train_aug os.makedirs(out_img, exist_okTrue) os.makedirs(out_txt, exist_okTrue) for name in os.listdir(img_dir): if not name.lower().endswith((.jpg, .jpeg, .png)): continue stem os.path.splitext(name)[0] img cv2.imread(os.path.join(img_dir, name)) txt_path os.path.join(txt_dir, stem .txt) if not os.path.exists(txt_path): continue # 读标注 with open(txt_path) as f: lines [l.strip() for l in f if l.strip()] # 只对图片做几何增强标注同步变换需要额外处理 # 这里演示的是仅颜色增强几何增强需同步变换多边形点 augmented transform(imageimg)[image] cv2.imwrite(os.path.join(out_img, stem _aug.jpg), augmented) # 颜色增强不改变标注直接复制 with open(os.path.join(out_txt, stem _aug.txt), w) as f: f.write(\n.join(lines))这段代码只做了颜色类增强因为几何变换需要同步变换多边形坐标处理起来更复杂。如果要做翻转和旋转得把归一化坐标反归一化、应用变换矩阵、再归一化回去。一个更省事的做法是直接用 ultralytics 的在线增强在data.yaml同级加一个augment.yaml或者在训练命令里传增强参数让框架在加载时实时变换标注自动跟着走。验证增强是否有效不能只看训练 loss。我的做法是固定一个测试子集每次训练完跑同一批图对比 mask 的 IoU 分布。如果增强后 IoU 的中位数提升但方差也变大说明增强引入了噪声需要降低增强强度。另一个技巧是留出 10 张图完全不参与训练也不参与增强作为「干净测试集」专门用来检测过拟合。迁移验证方面如果你手头有别的物流数据集哪怕只有几十张也可以拿来测一下这份数据训出的模型泛化能力。具体做法是冻结 backbone只微调分割头看 mask mAP 能不能在少量迭代内涨上去。如果涨不上去说明特征提取层学到的特征太贴合原数据集需要解冻更多层。从那以后我每次拿到小数据集都强制先跑一遍「原图 vs 增强图」的对比推理确认增强没有把条码这种小目标模糊掉再开始正式训练。希望帮到你。本文还有配套的精品资源点击获取
返回列表