从零构建钢笔检测数据集:VOC与YOLO双格式助力YOLOv8训练实战

从零构建钢笔检测数据集:VOC与YOLO双格式助力YOLOv8训练实战
简介这是一套面向目标检测任务的笔/钢笔检测数据集包含165张钢笔、签字笔等对象图像并配有165个VOC格式的XML标注文件可直接作为训练集或验证集使用。数据集适合希望训练YOLO系列模型的计算机视觉学习者也可用于物体检测算法的效果验证与对比测试尤其适合配合ultralytics-yolo-webui项目快速开展检测实验。资源共330个文件压缩包仅5.16MB轻量易下载其中165个jpg为原始图像样本165个xml为对应的目标框标注记录图像与标注文件一一对应常见检测框架均能直接解析使用。目前已有122人学习下载。借助这份标注完备的数据集读者可以节省自行采集与标注的时间集中精力完成YOLO检测任务的预处理、训练与推理体验完整工作流适用于课程教学、毕业设计或入门实践。 手头有个小项目要做一个“桌面物品自动识别”的功能第一个需求就是识别会议桌上都有哪些笔——钢笔、中性笔、圆珠笔最好还能区分一下。翻了几天开源数据集发现笔类检测的公开资源少得可怜COCO里虽然有但大多是“某人拿着笔在写字”这种场景真正俯拍、桌面、杂物堆里的钢笔目标几乎没有现成的。最后还是老老实实自己攒了一个“pen检测数据集”按VOCYOLO双格式整理用来训练YOLOv8。这一套走下来从拍照、标注、格式转换到训练调参、指标评估坑踩了不少但也总结出了一条可以反复用的流程。这篇就写给同样被“垂直小目标检测”折磨的朋友特别是准备自己做数据集的整个过程可以直接抄作业。这个场景很适合拿来当数据集实战的样板目标小、类内差异大、背景复杂、遮挡常见而且训练数据几乎为零基础可依赖。如果你也准备训练自己的目标检测模型不一定非是笔这篇内容里的数据组织方式、标注避坑、格式转换脚本、训练配置和评估方法都是通用的。1. 数据集的定位与整体规划——先想清楚要检测什么1.1 类目定义pen到底该怎么定数据集命名是“pen”但“pen”这个词很模糊。钢笔fountain pen、圆珠笔ballpoint pen、中性笔gel pen、铅笔pencil都算pen。我在做的时候面临两个选择方案A就一个类pen把所有笔归为一类模型只需要输出“这里有笔”方案B多类目比如fountain_pen、ballpoint_pen、pencil输出时还要区分具体类型。最终选了方案A作为v1版本。原因很直接第一类内差异大但类间边界模糊圆珠笔和中性笔在俯拍视角下几乎长得一样硬分会让标注的人抓狂第二业务需求其实是“桌面有没有笔、有几支”并不需要区分型号。方案B留给后续数据量上来后再扩展。类目定义这件事想清楚比动手做更重要因为后面的标注、评估、迭代全都被它绑架。1.2 数据采集数量、场景与多样性pen数据集的采集我分成了三路自己用手机在办公室、会议室、家里书桌拍的实拍图从无版权图库扒的桌面俯拍图以及从现有公开数据COCO里有笔的图片筛出来的可用帧。三路来源合计拿到了大约1200张原始图片。这个数量够不够如果只有单一场景300张就能训出一个能看的模型但桌面场景变化太大光线、背景、笔的朝向、是否带笔帽都会影响泛化。我的建议是单类目标至少500个标注实例如果你要分3类总实例数最好到2000以上。我清洗后剩下来能用的有效标注约900张图、1600个笔实例勉强够用。采集的时候有一个特别容易被忽略的点负样本。桌面上的笔筒、文具盒、U盘、充电线这些“非笔物品”要专门拍一批让模型见过“什么不是笔”否则推理时会把笔帽、笔芯、橡皮误判成目标。我大概加了150张纯负样本图对降低误检帮助很大。1.3 数据划分与目录组织规范数据准备好后第一件事就是目录结构。VOC格式和YOLO格式对目录要求不同我直接按下面这样组织后续转换脚本可以一键处理pen_dataset/ ├── images/ │ ├── train/ # 约720张 │ ├── val/ # 约180张 │ └── test/ # 约150张 ├── annotations/ │ ├── train/ # VOC xml每个图片对应一个xml │ ├── val/ │ └── test/ └── labels/ ├── train/ # YOLO txt每行class_id x_center y_center w h ├── val/ └── test/划分比例我用的是8:1:1但有个注意点train和val之间要按“场景来源”去重不能同一支笔、同一个桌面背景的图片既出现在train又出现在val。否则评估结果虚高部署到真实环境立刻现原形。我按拍摄场景和时间段做了分组切分保证验证集“没见过”训练集里的场景。2. 选择VOC还是YOLO格式标注规范与格式转换2.1 两种标注格式的核心区别圈子里最常用的检测标注格式就是VOCXML和YOLOTXT早期的目标检测公开数据集比如VOC2007、VOC2012带火了前者而YOLO系列训练框架把后者变成了事实标准。两者存的都是“目标在哪里”和“目标是什么”但差别很大对比项VOC XMLYOLO TXT坐标形式左上角x_min, y_min右下角x_max, y_max像素值归一化后的中心点x_center, y_center宽w高h0~1浮点数存储结构标签文件独立存储一棵XML树含object列表每行一个目标纯数字顺序固定可读性人可以直接读方便排查错误人读起来很费劲不如XML直观与框架契合老一代检测框架SSD、Faster R-CNN更常用YOLOv5/v8、Ultralytics系列原生支持日常排查标注错误时我都是用XML可视化训练框架则读取YOLO格式。所以两个格式同时保留而不是二选一是更稳妥的做法。2.2 标注规范遮挡、小目标、模糊样本标注阶段如果有条件用 labelImg 就够了比CVAT轻量。但真正决定数据集质量的是标注规范我这里踩过的坑总结成几条硬性规则完整目标为正样本笔完整出现在画面里不管角度多斜都要框出来遮挡超过50%不标一支笔被手掌盖住一半以上不标。模型会学到“半支笔”是目标推理时反而会对局部产生误检小目标宁可漏标不要错标笔尖、笔帽这类极小的目标框不准会污染训练。我的做法是短边小于图片宽度的5%就不标先用一轮大目标训练后期再单独补小目标旋转不矫正用旋转矩形框的标注方案比如DOTA那种对旋转目标更友好但YOLO原生只支持axis-aligned矩形框所以斜着的笔就用外接矩形框不要强行旋转图像。这里有个细节值得展开俯拍桌面上笔经常是斜着放的外接框会带进大量背景。我一开始很担心这个后来实践证明只要数据里各种角度都有YOLO能自己学会“笔的轮廓”是长条状的外接框带来的背景干扰会在训练中通过样本多样性消化掉。不需要一上来就上旋转框方案。2.3 标注格式转换XML转TXT 脚本标注完成后我用一个脚本把VOC XML批量转成YOLO TXT。核心逻辑是根据XML里的size拿到图片宽高然后把像素坐标归一化。这个脚本网上有很多版本但都不太贴合自己的目录结构我改了一个稳定版import xml.etree.ElementTree as ET import os def convert_voc_to_yolo(xml_dir, txt_dir, class_map): os.makedirs(txt_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() # 图片尺寸归一化必须用这个值不能写死 size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) txt_path os.path.join(txt_dir, xml_file.replace(.xml, .txt)) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] box obj.find(bndbox) x_min float(box.find(xmin).text) y_min float(box.find(ymin).text) x_max float(box.find(xmax).text) y_max float(box.find(ymax).text) # 防止坐标越界 x_min max(0, min(x_min, img_w - 1)) x_max max(0, min(x_max, img_w - 1)) y_min max(0, min(y_min, img_h - 1)) y_max max(0, min(y_max, img_h - 1)) # 坐标转换像素 - 归一化 x_center (x_min x_max) / 2 / img_w y_center (y_min y_max) / 2 / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h # 过滤掉无效目标过小或越界 if w 1e-5 or h 1e-5: continue lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: class_map {pen: 0} # 类名到id的映射后续扩展分类可以继续加 convert_voc_to_yolo(annotations/train/, labels/train/, class_map) convert_voc_to_yolo(annotations/val/, labels/val/, class_map)一个很容易踩的坑是XML里的size和图片真实尺寸不一致。转出来的TXT坐标必须与图片匹配否则训练时YOLO会警告“标签越界”甚至直接丢弃标签导致这个目标白标了。我跑了一次后发现从某些图库下载的图片被EXIF旋转过像素宽高和XML里对不上最后统一用脚本重写了size再转格式问题才彻底消失。3. 用YOLOv8训练自己的钢笔检测模型3.1 环境准备没有GPU怎么办训练目标检测模型GPU几乎是刚需。YOLOv8确实支持CPU训练但一张700张图片的数据集在CPU上跑300个epoch可能要十几个小时GPU只需要几十分钟。如果你手头没有独立显卡有两个办法用云端GPU比如Colab的免费T4或者各种云主机的GPU实例先剪裁图片尺寸比如把训练图片改成640x640能显著降低算力开销。我用的是本地一张RTX 306012GB显存batch size能开到16跑300个epoch的耗时大约40分钟非常舒服。如果你的显卡只有6GB显存建议batch size降到8图片尺寸降到512x512否则容易显存溢出。安装依赖就一行pip install ultralyticsultralytics这个包已经把YOLOv8的训练、验证、导出全部封装好了不需要自己写训练循环。它的底层是PyTorch所以PyTorch的版本最好提前装好尤其是GPU版别等跑起来才发现CUDA版本不对。3.2 数据配置与训练命令YOLOv8训练需要一份dataset.yaml文件告诉框架数据在哪里、有几个类。我的配置长这样path: /home/user/pen_dataset # 数据集根目录用绝对路径最稳 train: images/train # 训练图片相对路径 val: images/val # 验证图片相对路径 test: images/test # 测试图片相对路径可选 nc: 1 # 类别数量我们这个数据集只有pen names: 0: pen贴一个容易踩的坑path里如果用相对路径YOLOv8会以“当前工作目录”作为基准一旦你从别的目录启动训练路径就全部失效报image not found。改用绝对路径能一次性省掉这个烦恼。而我自己的做法是直接在当前工作目录下放一个data.yaml写作train: /home/user/pen_dataset/images/train val: /home/user/pen_dataset/images/val nc: 1 names: [pen]然后启动训练yolo detect train datapen.yaml modelyolov8s.pt epochs300 imgsz640 batch16 patience30 projectpen_results nameexp1选yolov8ssmall而不是yolov8nnano或yolov8mmedium是针对性考量nano在移动端很有优势但精度偏低medium在3060上训练还能跑但推理速度和迭代速度都偏慢。s在精度和速度之间比较平衡。对于一个单类小目标检测任务模型容量不需要太大先让模型收敛再根据结果决定是否换成更大的模型。3.3 训练过程中怎么看Loss与指标曲线训练开始后终端会滚动输出每个epoch的loss值、精度和召回率。新手容易犯的毛病是只顾着看“数字掉了没”完全忽略曲线趋势。YOLOv8在project/exp1/目录下会生成results.png包含多个子图。我主要关注两组曲线box_loss和cls_loss训练集和验证集的loss是否同步下降验证集loss如果先降后升说明过拟合mAP50和mAP50-95验证集上的平均精度mAP50是IoU阈值0.5下的精度mAP50-95是0.5到0.95每隔0.05取一次的平均值后者对框的定位精度要求更苛刻。在笔检测这个任务里mAP50到0.9以上算不错mAP50-95能到0.75就已经很好了。因为笔是长条形目标和正方形的目标比它对定位误差天然更敏感同一个像素偏差在长条目标上会拉低更多IoU。关于patience30这个参数它的含义是30个epoch内验证集指标没有提升就自动停止。这个机制非常有用——训练到后面观察loss还在降但mAP不再涨说明泛化能力已经到头继续跑只会浪费时间。我前几次训练没设这个参数白白多跑了十几个小时后来固定设置patience30省心很多。4. 模型评估与常见问题排查实录4.1 评价指标到底看哪个mAP50和mAP50-95训练完成后运行验证命令可以输出评估指标yolo detect val datapen.yaml modelpen_results/exp1/weights/best.pt你会看到Precision、Recall、mAP50、mAP50-95四组数字。我个人的评判习惯是分场景如果你的目标是“找得到就行”比如统计桌上有几支笔重点看Recall漏检比误检更致命如果你的目标是“定位准确”比如机械臂去抓取这支笔重点看mAP50-95因为框偏一点机械臂就抓偏了如果目标是“分类判别”比如判断画面里有没有违禁品重点看Precision宁可不报告也不能乱报。我的pen模型最终在测试集上的指标是Precision 0.93、Recall 0.88、mAP50 0.92、mAP50-95 0.76。对于单类长条形目标这个结果在可用范围。如果你看到自己的mAP50只有0.6、0.7不用慌先看数据集规模再看标注质量最后再考虑换模型。4.2 训练效果差的排查清单如果训练结果不理想我的排查顺序是有讲究的按这个顺序走能省大量时间现象优先排查项loss不降标注类别名和yaml中names数量不匹配mAP很高但实际推理很差训练集和验证集切分有重叠数据分布没有分开小目标完全检不出原图尺寸太大但训练imgsz太小目标被压缩成一两像素误检特别多负样本太少模型没学会“什么不是笔”一个目标框出多个框置信度阈值太低或NMS参数需要调整这些坑我全都踩过一遍。印象最深的是第一次训练时mAP50在验证集上高达0.96心里美滋滋拿去测试结果一测就像个傻子——后来发现是因为图库图片来自同一个产品摄影师的同一批拍摄参数train和val里出现了大量几乎一模一样的图。重新按场景分组切分后mAP掉到了0.85左右但真实场景表现反而变好了。评价指标虚高的现象在垂直数据集上非常常见务必警惕。4.3 小目标检测与数据增强技巧笔在俯拍画面中通常算“中小目标”尤其拍摄距离远一点整支笔的长度可能只有图像宽度的30%左右。YOLOv8默认在训练时会做mosaic四图拼接、仿射变换等数据增强对小目标有点用但还不够。我试过两个针对性手段把imgsz从640提高到896让目标在输入图像上占据更多像素用SAHISlicing Aided Hyper Inference做推理把大图切成小图分别检测再合并结果。实测提高imgsz后mAP50-95涨了2~3个点代价是训练速度下降约30%。如果你的场景是固定摄像头俯拍建议给硬件加一个最小目标尺寸限制低于某个尺寸直接不检测可以过滤掉大量远处的干扰物体。另外如果你原本用的是YOLOv5/v8老版本可以试试给“小目标检测头”加上——YOLOv8自身已经支持多尺度特征融合不需要额外加检测头。早期的YOLO版本想要小目标效果好往往需要在颈部网络里加一层更浅的特征层这个改造比较麻烦v8时代直接换大图尺寸更省心。4.4 训练调试环境的一些“题外话”这次训练过程中我在本机上还遇到一个和YOLO完全无关的系统级报错值得顺手提一嘴。有一次重启电脑后打开终端登录界面和桌面出现了一段failed to load plugins web boot: 1 entry did not activate dsh-ui-tweaks的提示桌面主题效果没生效但系统能正常用。查了一圈发现是桌面的UI增强小插件没有正确加载属于GNOME的一个老问题常见原因是插件版本和桌面环境不匹配或者在系统更新后被disable。解决办法是检查插件管理器重新启用对应插件或者干脆卸载这个主题插件。这个问题不影响YOLO训练但很容易让人误以为是环境坏了白白折腾半天。5. 部署阶段的一个提醒别看漏了“置信度阈值”模型训练完导出成ONNX或者TensorRT之后部署时最容易忽略的一个参数就是conf_thres置信度阈值。训练时默认的阈值是0.25但实际部署场景里如果背景复杂0.25会导致很多误检尤其是负样本不够的时候。我自己的测试结论是办公室场景下把conf_thres调到0.45误检少了一半召回率只损失两个点但在光线较暗的场景阈值调太高又会出现漏检。所以建议部署前在目标环境的图片上做一次小规模“阈值扫描”从0.3到0.6每0.05测一次画一个precision-recall曲线选择曲线拐点对应的阈值。这一步很不起眼但能直接影响用户体验效果立竿见影。最后再分享一个小技巧做pen数据集的经验我后来直接复用到“X光安检物品检测数据集”上两者都按VOCYOLO双格式组织都用了同样的标注规范和训练流程。那个项目里目标更小、遮挡更严重但是靠着数据集中间多加了大量负样本以及imgsz提高到1024最终训练结果比预期好很多。数据集这件事没有玄学标注规范、格式转换、训练配置、阈值调优每一步都在为最后那几个点的精度买单。希望这份流程能让你少走一些弯路。本文还有配套的精品资源点击获取

最新新闻

日新闻

周新闻

月新闻