ARTICLE DETAIL

资讯详情

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

包裹与条码实例分割数据集:从标注格式到YOLOv8训练落地全链路

包裹与条码实例分割数据集:从标注格式到YOLOv8训练落地全链路 简介这份包裹与条码实例分割数据集面向物流自动化、智能仓储与计算机视觉方向的研究者和开发者用于训练模型精确识别包裹与条码轮廓解决分拣流水线、库存盘点及安防监控中的定位与计数问题。资源共322个文件以160张JPEG实景图片和160个YOLO格式TXT标注为主另含1个yaml配置文件与1份docx说明文档压缩包约13.97MB标注采用多边形坐标点可精确覆盖对象轮廓兼容YOLO等主流框架直接用于实例分割训练。数据划分训练集147张、验证集6张、测试集7张涵盖barcode、package、packages三类覆盖单包裹、多包裹及条码标签等物流核心元素。目前已有207人学习下载。读者可借此快速搭建实例分割实验基线省去数据采集与标注成本并围绕真实物流场景验证分拣、库存追踪与异常检测算法提升模型泛化能力。1. 包裹与条码实例分割数据集从标注格式到训练落地的完整链路快递分拣线上一个纸箱贴着面单经过工业相机算法要在 30 毫秒内同时回答两个问题包裹的轮廓在哪面单上的条码区域在哪。这不是目标检测能搞定的活——检测框会把相邻包裹叠在一起条码倾斜 45 度时矩形框里一半是背景。实例分割才是正解它输出的是像素级掩码每个包裹、每个条码都有独立的轮廓。包裹与条码实例分割数据集.zip 这类资源解决的正是「没有标注数据」这个最卡脖子的环节。它适合三类人做物流分拣视觉的算法工程师、想用 YOLO 实例分割练手但缺行业数据的学生、以及需要快速验证条码定位方案的产品团队。下面从数据解压后的目录结构讲起一路走到训练命令和踩坑记录。2. 拆开压缩包目录结构、标注格式与标签体系拿到一个实例分割数据集第一件事不是急着训练而是搞清楚它到底长什么样。包裹与条码这类工业场景数据集通常采集自固定工位的工业相机图像分辨率高、背景相对单一但标注质量参差不齐。解压后先别动代码用命令行把目录树和文件数量摸清楚。2.1 解压后的目录长什么样常见做法是数据集按 images 和 annotations 两个顶层目录组织images 下再分 train、val、testannotations 里放对应的标注文件。先跑一遍统计命令# 统计图像数量和标注文件数量确认是否一一对应 find ./dataset/images -type f \( -name *.jpg -o -name *.png \) | wc -l find ./dataset/annotations -type f -name *.json | wc -l # 查看目录层级确认没有多余的嵌套 tree -L 3 ./dataset # 抽查一张图像的尺寸和通道数 python3 -c from PIL import Image img Image.open(./dataset/images/train/000001.jpg) print(尺寸:, img.size, 模式:, img.mode) 这三条命令分别回答三个问题图像和标注是否配对、目录结构是否规整、图像分辨率是否统一。如果图像数量是 5000 而标注只有 4800说明有 200 张图没标或者标注文件命名不匹配这个坑不提前发现训练时会在 DataLoader 里报索引越界。参数说明-L 3限制目录树深度避免嵌套太深刷屏wc -l统计行数即文件数。如果图像格式混杂了 jpg 和 png后续转 COCO 格式时要统一处理否则某些框架的读取器会静默跳过。2.2 标注格式判定COCO JSON 还是 YOLO TXT实例分割的标注格式主流就两种COCO 的 JSON多边形点集和 YOLO 的 TXT归一化多边形坐标。打开一个标注文件看头部就能判断import json with open(./dataset/annotations/train.json, r) as f: data json.load(f) # COCO 格式的顶层键 print(顶层键:, list(data.keys())) # 典型输出: [images, annotations, categories] # 看一个标注样本的结构 ann data[annotations][0] print(标注字段:, list(ann.keys())) # 典型输出: [id, image_id, category_id, segmentation, area, bbox, iscrowd] # 看类别定义 for cat in data[categories]: print(cat[id], cat[name])如果segmentation字段是嵌套列表[[x1,y1,x2,y2,...]]那就是多边形格式可以直接用于实例分割训练。如果只有bbox没有segmentation那这个数据集严格来说是检测数据集需要额外做掩码标注才能用于分割——这是最常见的预期落差。包裹与条码场景的类别体系通常很简洁package包裹和barcode条码两类偶尔会有label面单作为第三类。类别数少是好事训练收敛快但也意味着模型容易过拟合到背景纹理后面讲数据增强时会展开。2.3 标签分布统计别让长尾类别拖垮训练在动手转格式之前先统计每个类别的实例数量和掩码面积分布。这一步能提前暴露「条码实例太少」或「小目标占比过高」的问题import json from collections import Counter with open(./dataset/annotations/train.json, r) as f: data json.load(f) cat_map {c[id]: c[name] for c in data[categories]} counter Counter() area_sum {} for ann in data[annotations]: name cat_map[ann[category_id]] counter[name] 1 area_sum.setdefault(name, []).append(ann[area]) for name, cnt in counter.items(): areas area_sum[name] small sum(1 for a in areas if a 32*32) print(f{name}: 实例数{cnt}, 小目标占比{small/len(areas):.1%}, 平均面积{sum(areas)/len(areas):.0f})如果条码类的小目标占比超过 60%训练时要把输入分辨率调高比如 1024 而非 640否则条码的掩码会糊成一团。包裹类通常面积大但边缘容易被遮挡标注时如果只标了可见部分模型学到的掩码会不完整。提示统计结果里如果某个类别的实例数少于总实例数的 5%考虑用过采样或 copy-paste 增强否则该类别的 AP 会低得没法看。3. 转成 YOLO 分割格式脚本、参数与四个边界坑COCO JSON 转 YOLO TXT 是实例分割训练前绕不开的一步。网上脚本很多但直接拿来用大概率翻车因为包裹与条码场景有几个特殊之处图像分辨率不统一、条码多边形点序可能不是顺时针、部分标注有自相交。下面这个脚本是我在实际项目里改过三版的版本。3.1 转换脚本的核心逻辑import json import os from PIL import Image def coco_to_yolo_seg(json_path, img_dir, out_dir): with open(json_path, r) as f: data json.load(f) # 建立 image_id 到文件信息的映射 img_info {img[id]: img for img in data[images]} # 类别 id 重映射为 0 起始的连续整数 cat_ids sorted([c[id] for c in data[categories]]) cat_remap {old: new for new, old in enumerate(cat_ids)} os.makedirs(out_dir, exist_okTrue) for ann in data[annotations]: img img_info[ann[image_id]] w, h img[width], img[height] seg ann[segmentation] # 跳过空掩码和 iscrowd 标注 if not seg or ann.get(iscrowd, 0) 1: continue lines [] for poly in seg: # 多边形至少需要 3 个点 if len(poly) 6: continue # 归一化并裁剪到 [0, 1] coords [] for i in range(0, len(poly), 2): x min(max(poly[i] / w, 0.0), 1.0) y min(max(poly[i1] / h, 0.0), 1.0) coords.append(f{x:.6f} {y:.6f}) cls_id cat_remap[ann[category_id]] lines.append(f{cls_id} .join(coords)) if not lines: continue # 输出文件名与图像同名扩展名改为 txt stem os.path.splitext(img[file_name])[0] with open(os.path.join(out_dir, stem .txt), w) as f: f.write(\n.join(lines)) print(f转换完成类别映射: {cat_remap}) coco_to_yolo_seg( ./dataset/annotations/train.json, ./dataset/images/train, ./dataset/labels/train )逻辑说明先建立 image_id 到宽高的映射因为归一化必须用原图尺寸类别 id 重映射是因为 COCO 的 category_id 可能不连续比如 1 和 5YOLO 要求从 0 开始连续编号。每个多边形独立成行格式是类别 x1 y1 x2 y2 ...坐标归一化到 0 到 1 之间。参数说明min(max(..., 0.0), 1.0)这步裁剪不能省有些标注的多边形会超出图像边界不裁剪的话 YOLO 训练时直接报错。len(poly) 6过滤掉少于 3 个点的退化多边形这种标注在包裹边缘遮挡场景里很常见。3.2 四个必踩的边界坑第一个坑图像尺寸不统一。COCO JSON 里记录的 width 和 height 是标注时的尺寸但如果图像被重新缩放保存过实际尺寸和记录不符归一化坐标就会整体偏移。解决办法是转换时用 PIL 重新读一次实际尺寸和 JSON 里的对比不一致就以实际为准并打印警告。第二个坑多边形点序。YOLO 分割训练对点序没有强制要求但某些数据增强库比如 albumentations 的某些版本在处理自相交多边形时会崩溃。检测方法是用 shapely 验证每个多边形的有效性from shapely.geometry import Polygon def is_valid_polygon(coords): # coords 是 [x1, y1, x2, y2, ...] 格式 points [(coords[i], coords[i1]) for i in range(0, len(coords), 2)] poly Polygon(points) return poly.is_valid and poly.area 0无效的多边形要么修复用 buffer(0)要么直接丢弃。丢弃会损失一些标注但比训练中途崩溃强。第三个坑类别不平衡导致的标签文件空行。如果一张图里只有包裹没有条码转换后的 txt 文件只有包裹的行这没问题。但如果一张图里所有标注都是 iscrowd 被跳过了txt 文件会是空的YOLO 训练时会把空文件当作负样本如果负样本比例过高模型会偏向预测背景。第四个坑文件名冲突。train 和 val 里如果有同名图像比如都叫 000001.jpg转换后的 txt 会互相覆盖。解决办法是在输出文件名里加上 split 前缀或者转换前先检查重名。注意转换完成后务必用wc -l对比原始 JSON 里的标注数和生成的 txt 行数差值超过 5% 就要回头查是哪个过滤条件砍多了。4. 用 YOLOv8-seg 跑通第一次训练配置文件与显存调优数据转好了接下来是训练。YOLOv8-seg 是目前上手最快的实例分割方案一条命令能跑但默认参数在包裹与条码场景下大概率效果一般。这一章讲清楚配置文件怎么写、关键参数怎么调、显存不够时怎么降配。4.1 数据集 YAML 的写法YOLO 需要一个 YAML 文件告诉它数据在哪、有几类# package_barcode.yaml path: /home/user/dataset # 数据集根目录 train: images/train val: images/val test: images/test names: 0: package 1: barcodepath用绝对路径避免训练时因为工作目录变化找不到数据。names的键必须从 0 开始连续和转换脚本里的 cat_remap 对应。如果转换时打印的映射是{1: 0, 3: 1}说明原始 JSON 里类别 id 是 1 和 3YAML 里写 0 和 1 就对了。4.2 训练命令与关键参数yolo segment train \ datapackage_barcode.yaml \ modelyolov8s-seg.pt \ epochs100 \ imgsz1024 \ batch8 \ lr00.01 \ lrf0.01 \ patience20 \ augmentTrue \ mosaic1.0 \ copy_paste0.3 \ projectruns/segment \ namepackage_barcode_v1参数逐个说imgsz1024是因为条码是小目标640 分辨率下条码掩码的 IoU 会掉 10 个点以上。batch8是 1024 分辨率下 8G 显存的保守值显存够可以加到 16。lr00.01是初始学习率实例分割比检测对学习率更敏感太大容易在早期把掩码分支学崩。patience20是早停耐心值验证集 20 轮不提升就停省时间。copy_paste0.3是实例分割特有的增强把不同图的实例复制粘贴到一张图上对包裹这种可分离的物体效果很好但条码粘贴时要注意方向一致性否则模型学到旋转不变的错误特征。如果显存不够优先降batch而不是imgsz因为分辨率对条码掩码质量的影响远大于 batch size。降到 batch4 还 OOM再考虑用yolov8n-seg.pt换小模型。4.3 训练过程中的监控指标训练日志里重点看三个指标metrics/mAP50-95(M)是掩码 APmetrics/mAP50-95(B)是检测框 APtrain/seg_loss是分割损失。正常情况下掩码 AP 会比检测框 AP 低 3 到 8 个点如果低超过 15 个点说明掩码分支没学好检查标注多边形是否太粗糙。seg_loss在前 10 轮应该快速下降如果震荡不降把lr0降到 0.005 再试。验证集的可视化结果用yolo segment predict生成yolo segment predict \ modelruns/segment/package_barcode_v1/weights/best.pt \ sourcedataset/images/val \ saveTrue \ conf0.25 \ iou0.5 \ projectruns/predict \ nameval_visconf0.25是置信度阈值包裹与条码场景建议先设低一点看召回漏检比误检代价大。iou0.5是 NMS 的 IoU 阈值如果相邻包裹贴得很近调到 0.6 避免把两个包裹合并成一个。5. 避坑与排查标注、增强、显存和评估的五个翻车现场这一章记录的是我在包裹与条码数据集上真实踩过的坑每个都按现象、原因、解决来写。有些坑不遇到一次根本想不到提前看了能省至少两天调试时间。5.1 掩码边缘锯齿严重AP 虚高但可视化很差现象训练日志里掩码 AP 到了 0.75但预测结果可视化时包裹边缘像狗啃的条码掩码甚至盖不住整个条码。原因标注多边形点数太少。包裹与条码数据集如果是用矩形框辅助标注的多边形可能只有 4 到 8 个点模型学到的掩码就是粗糙的多边形近似。COCO 评估指标对边缘不敏感所以 AP 看起来还行但实际用的时候边缘精度不够。解决如果原始标注点数少于 16 个用多边形插值补点。简单做法是在相邻两点之间线性插值让每个边至少分成 4 段。更好的做法是用 SAMSegment Anything Model对每个实例做一次精修但那是另一个工作量了。至少要在训练前把点数补到 16 以上。5.2 条码类别 AP 始终为 0现象训练 50 轮后包裹的掩码 AP 有 0.7条码的 AP 一直是 0。原因条码实例在训练集里太少或者条码的掩码面积太小小于 8x8 像素YOLO 的掩码分支在低分辨率特征图上根本覆盖不到。另一个可能是类别 id 映射错了条码的标注被当成了背景。解决先检查转换后的 txt 文件里有没有类别 id 为 1 的行。如果没有回头查 JSON 里条码的 category_id 是不是被 cat_remap 漏掉了。如果有但 AP 还是 0把imgsz提到 1280同时把copy_paste里条码的粘贴概率单独调高。还可以在 YAML 里给条码类加cls_pw2.0的类别权重YOLOv8 支持通过cls参数传类别权重。5.3 训练到第 30 轮突然 loss 变 NaN现象前 30 轮 loss 正常下降第 31 轮突然变成 NaN之后所有轮次都是 NaN。原因十有八九是某个批次的标注里有非法值。最常见的是多边形坐标归一化后出现了负数或大于 1 的值或者多边形自相交导致面积计算为负。另一个可能是学习率在 warmup 阶段冲太高。解决在 Dataset 的__getitem__里加断言检查每个多边形的坐标范围和多边形有效性。把lr0从 0.01 降到 0.005warmup_epochs从默认 3 加到 5。如果还 NaN用torch.autograd.set_detect_anomaly(True)定位到具体是哪一层出的问题。5.4 验证集 AP 比训练集低 20 个点现象训练集掩码 AP 0.85验证集只有 0.65差距大得不正常。原因包裹与条码数据集的 train 和 val 如果是按时间划分的比如上午采集的做 train下午的做 val光照变化会导致分布偏移。另一个常见原因是 val 集里的图像分辨率或背景和 train 差异大。解决先做数据分布对比统计 train 和 val 的亮度均值、对比度、图像尺寸分布。如果差异明显要么重新随机划分要么在增强里加颜色抖动hsv_h0.015, hsv_s0.7, hsv_v0.4让模型对光照不敏感。如果 val 里有 train 没见过的背景考虑用 domain adaptation 或者干脆把 val 里的一部分加进训练。5.5 推理时掩码比检测框慢 5 倍现象部署时发现分割推理耗时 50ms而检测只要 10ms达不到产线节拍。原因YOLOv8-seg 的掩码分支需要额外的原型掩码计算和上采样在 CPU 上尤其慢。如果部署环境没有 GPU50ms 是正常的。解决如果必须用 CPU把imgsz降到 640掩码质量会降但速度能到 20ms 以内。或者用yolov8n-seg替代yolov8s-seg参数量少一半。另一个思路是只在条码区域做分割包裹用检测框因为包裹的轮廓精度对分拣影响不大条码的像素级定位才是关键。这种混合策略能把推理时间压到 15ms 左右。6. 把掩码质量再提一档从 0.75 到 0.85 的三个实操技巧训练跑通、AP 到 0.75 之后再往上提每一分都很难。这一章讲三个我在实际项目里验证过有效的技巧不需要换模型架构只改数据和处理流程。第一个技巧是掩码后处理的形态学优化。模型输出的掩码边缘通常有毛刺用 3x3 的椭圆核做一次开运算再闭运算能去掉孤立噪点同时平滑边缘。在 Python 里用 OpenCV 实现import cv2 import numpy as np def refine_mask(mask, kernel_size3): # mask 是 0/1 的二值掩码uint8 类型 kernel cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernel_size, kernel_size)) # 开运算去噪点 opened cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) # 闭运算填小洞 closed cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel) return closedkernel_size 用 3 就够了用 5 会把条码的细条纹也腐蚀掉。这个操作在验证集上能把掩码 AP 提 1 到 2 个点代价是每张图多 2ms 后处理时间。第二个技巧是难例挖掘。训练完第一版后用模型在训练集上跑一遍预测把掩码 IoU 低于 0.5 的样本挑出来人工检查标注是否有误。包裹与条码数据集里最常见的标注错误是条码被遮挡时只标了可见部分模型学到的掩码也是残缺的。把这些样本的标注补全后加入训练第二轮训练时条码 AP 能提 5 个点以上。第三个技巧是测试时增强TTA。推理时把图像水平翻转、多尺度缩放各跑一次把掩码结果平均。YOLOv8 自带 TTA 支持yolo segment predict \ modelbest.pt \ sourcetest_images \ augmentTrue \ conf0.2 \ iou0.6augmentTrue开启 TTA推理时间变成 3 倍但掩码 AP 能提 2 到 3 个点。如果产线节拍允许这个是最省事的提点方式。不允许的话只在离线抽检环节用 TTA在线推理用单次。这三个技巧叠加在包裹与条码数据集上从 0.75 提到 0.85 是可行的。但要注意如果验证集本身标注质量不高提点会遇到天花板——这时候该做的是回头修标注而不是继续调模型。我自己的习惯是每轮训练后抽 20 张验证集的可视化结果肉眼过一遍看到掩码明显不对的就记下来攒够 50 张就集中修一轮标注。这个习惯比任何调参都管用。希望帮到你。本文还有配套的精品资源点击获取
返回列表