
简介面向计算机视觉目标检测方向的开发者与学习者这份数据集聚焦工具扳手banshou单一类别兼容YOLO与Pascal VOC两种常见标注格式可直接用于目标检测模型的训练、调参与评估。压缩包共2000个文件主要包含xml与txt标注文件分别对应VOC与YOLO格式可适配不同检测框架整体大小仅29.56MB。当前已有359人学习下载。数据集中包含1003张扳手图像标注类别为banshou总标注框数达到2097个经labelImg工具统一标注覆盖不同位置、视角与光照条件下的目标。使用者拿到数据后即可开始算法试验也可作为目标检测入门练习数据用于理解数据标注结构、格式转换与模型评估流程在工业场景中还可进一步支撑工具清点、物料管理与安全监管等细分任务。整体数据组织清晰适合从入门到进阶的不同阶段学习者按需使用。1. 拿到这个扳手数据集第一件事不是训练而是验证一个标好 1003 张图片、2097 个框的扳手数据集看起来直接就能丢进 YOLO 开训。但真实情况是单类别数据集最容易在“格式没问题”的错觉下翻车XML 里是绝对像素坐标TXT 里是归一化中心坐标两边要是没有严格对齐训练出来的模型会拿错框甚至学不到任何特征。我拆过的目标检测项目里至少有三分之一的时间花在标注文件核查上而不是调参。这个数据集的价值在于它同时给了 Pascal VOC 的 XML 和 YOLO 的 TXT而且类别只有一个banshou。这意味着你可以省掉类别映射的麻烦专注把坐标换算、数据划分、训练验证和迁移复用这条链路走通。适合做两类事一是刚接触目标检测、想用少量数据跑通 YOLOv5/YOLOv8 全流程的开发者二是做工业分拣、工具识别、机械手抓取这类有单一零件识别需求的人。下面从标注格式切入把这份资源讲透。2. VOC 与 YOLO 格式的坐标体系差异与批量互转2.1 两种格式的物理意义完全不同Pascal VOC 的 XML 用bndbox节点存xmin, ymin, xmax, ymax这四个值是像素坐标单位是图片的绝对像素点。用 labelImg 标注时鼠标拖出来的矩形框就是这套坐标。它直观但问题在于它依赖图片尺寸同一张图缩放后坐标就失真。YOLO 格式的 TXT 每一行是五个数字对应class_id, x_center, y_center, width, height后四个值都是归一化比例用像素值除以图片宽度或高度得到取值范围落在 0 到 1 之间。这样做的原因是 YOLO 的锚框和损失计算工作在特征图上归一化坐标能直接映射到不同尺度的网格而不需要额外缩放。一个最常见的坑是把 XML 的xmin/xmax直接除以图像宽度得到两个值就当成 YOLO 的中心坐标和宽度。正确的换算关系是x_center (xmin xmax) / 2.0 / img_width y_center (ymin ymax) / 2.0 / img_height width (xmax - xmin) / img_width height (ymax - ymin) / img_height逻辑上先求框的中心像素位置再归一化宽高同样要统一到 0-1 区间。直接拿xmin / img_width当中心点得到的框会整体偏向左上角损失函数从一开始就无法收敛。2.2 标注文件的字段与命名规律这个数据集的 TXT 文件命名是xyxr_banshou_380.txt这样的编号形式图片和 XML 应该保持同名前缀这是 labelImg 默认的保存习惯。你解压后要做一次文件名匹配检查因为实际操作中常出现 TXT 存在但 XML 缺失、或图片被误删的情况。VOC 与 YOLO 字段对照表信息项VOC XML 表达YOLO TXT 表达类别名称namebanshou/name类别索引0框左上角xmin, ymin无直接表达框右下角xmax, ymax无直接表达框中心需计算x_center, y_center框宽高需计算width, height坐标基准像素绝对值归一化比例单类别数据集在 YOLO 里固定用索引0不需要额外配置类别名。但如果后续要加入其它工具类别比如锤子、螺丝刀原有 TXT 的第一列就会变成0、1、2等VOC 侧则要同步新增name字段。这个数据集现在只有banshou一个类训练时nc1是确定的不用纠结映射表。2.3 手工编写 VOC 转 YOLO 脚本的双格式校验虽然压缩包里已经有了 TXT但往往只有你自己写过一遍转换代码才不会在别人给的标注文件里被绕晕。下面这个脚本既能把 XML 转成 YOLO也能反向校验已有 TXT 是否跟 XML 描述的是同一个框区域。import xml.etree.ElementTree as ET import os def voc_xml_to_yolo(xml_path, out_dir): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) yolo_lines [] for obj in root.iter(object): cls_name obj.find(name).text # 单类别数据集banshou 直接映射到 0多类别时需要建立字典 cls_id 0 box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h yolo_lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) txt_name os.path.splitext(os.path.basename(xml_path))[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(yolo_lines)) # 遍历 data 目录下所有 xml 文件 for xml_file in os.listdir(data): if xml_file.endswith(.xml): voc_xml_to_yolo(os.path.join(data, xml_file), data/yolo_labels)这段代码先读 XML 里的图片宽高再遍历每一个object节点用四个像素坐标算子算出归一化的中心点、宽高。输出精度保留 6 位小数足够 YOLO 使用。跑完后你得到的 TXT 应当和原压缩包里的 TXT 一致如果有偏差优先怀疑 XML 中是否存在 rotated bounding box 或多边形标注这类对象 labelImg 里通常表现为robndbox本脚本无法处理。2.4 缺少分割路径的含义摘要里特别提到“不包含分割路径的 txt 文件”这是指压缩包里没有像train.txt、val.txt这样的路径清单文件。很多数据集会用单独的 TXT 列出训练和验证图片的路径便于直接配合ImageFolder读取。这份数据没给需要自己按比例划分。我的建议是不要在训练代码里手动写死文件列表而是先搭建目录结构再用随机划分脚本生成train.txt和val.txt。划分完检查每个集合中的图片路径真实存在避免训练时因为路径错位报 file not found 错误。3. 用扳手数据集跑通 YOLOv8 全流程3.1 划分训练集与验证集让模型不只是记住了图片1003 张图片全部拿来训练不是不行但你没留验证集的话YOLOv8 训练时的 P/R/mAP 曲线全是假的调参没有任何依据。一般工业场景按 9:1 或 8:2 划分训练集和验证集如果后续想正式评估泛化能力建议从已有数据里再留出 100 张做测试集。import os import random from pathlib import Path data_root Path(data) imgs list(data_root.glob(*.jpg)) random.seed(42) random.shuffle(imgs) val_ratio 0.2 val_cnt int(len(imgs) * val_ratio) val_imgs imgs[:val_cnt] train_imgs imgs[val_cnt:] def write_split(img_list, txt_path): with open(txt_path, w) as f: for img in img_list: f.write(str(img.resolve()) \n) write_split(train_imgs, train.txt) write_split(val_imgs, val.txt)用绝对路径写入避免后续切换工作目录导致的路径失效。随机数种子固定为 42可以复现每一次划分方便对比不同超参数的训练效果。划分完成后确认train.txt和val.txt里的图片在data文件夹中都能找到同时每个.jpg必须有对应的.txt标注文件否则 YOLOv8 会静默跳过无标注的图像。3.2 编写 banshou.yaml 并处理单类别配置YOLOv8 使用 YAML 文件描述数据集的路径、类别数量和类别名。重点在于path字段它决定了后面所有相对路径的基准目录。如果你把data文件夹放在项目根目录下并且train.txt和val.txt也在里面可以这样写path: ./data train: train.txt val: val.txt nc: 1 names: [banshou]如果写成train: images/train这种形式就要求目录结构刚好是data/images/train但这份数据集的默认组织方式不是那样所以用 TXT 路径清单最稳妥。nc: 1必须和 TXT 标注第一列的最大索引值加一相等如果标注文件里出现第一列为1的行说明类别名称应该有两个此时要回去检查是否有其他类别被误标成banshou。3.3 选择合理的超参数避免 1000 张图就过拟合训练命令本身不复杂复杂的是知道每个参数为什么这么调。扳手是刚性物体外观变化不大但旋转角度和光照变化较多这决定了对degrees数据增强的依赖比较强而flipud可以关掉因为实际场景中扳手很少倒置放置。yolo detect train databanshou.yaml modelyolov8s.pt epochs100 imgsz640 batch16 patience20 degrees180 flipud0 scale0.4yolov8s是速度和精度的平衡点1000 张图训练yolov8m或yolov8l容易过拟合。imgsz640对扳手这类中小目标足够原始图片如果不是正方形YOLOv8 会自动缩放填充。batch16根据显存调整如果显存只有 6GB 减到 8。patience20表示验证集指标连续 20 轮不提升就早停。常用超参说明表参数值作用epochs100总数配合 early stopping 实际可能 40-60 轮停imgsz640输入分辨率越大对小目标更友好但更吃显存degrees180训练时随机旋转角度扳手方向多变所以开满scale0.4随机缩放 40%模拟远近变化patience20验证集 mAP 连续 20 轮不升则停止这里把degrees180写进训练命令是因为扳手在真实工作台上可能出现任意朝向这种旋转增强比加大scale更能提升泛化能力。还有一点如果训练到后半段发现cls_loss和dfl_loss下降很慢但box_loss还行大多是锚框和旋转增强的配合问题尝试减小degrees到 90 再跑一轮对比。3.4 训练日志的解读从损失值到 mAP 曲线YOLOv8 每轮会打印类似box_loss, cls_loss, dfl_loss, precision, recall, mAP50, mAP50-95的指标。单类别数据集的cls_loss通常很快降到很低不用特别关注重点是box_loss和dfl_loss是否平滑下降。mAP50是 IoU 阈值 0.5 时的平均精度扳手这类形状规则的物体如果mAP50在 0.9 以上说明标注质量不错。mAP50-95更严格它把 IoU 从 0.5 到 0.95 每隔 0.05 算一次再平均。单类别数据集这两个值的差距如果超过 0.3大概率是标注框边缘和物体轮廓贴合不紧边框预测不够精确。4. 训练前先做数据体检别把标注错误喂给模型4.1 文件数量与替代命名编号的核对压缩包叫 1000 张实际包含 1003 张这不算什么问题但你要清楚多出来的 3 张是怎么回事。从文件名xyxr_banshou_380.txt这类编号看可能是拍摄时对几个样本重新补拍后编号漂移导致总数略超标题数字。训练脚本按目录扫描而不是按数字范围扫描所以不影响使用。真正需要核对的是以下三个数量的对应关系JPG 文件个数、XML 文件个数、TXT 文件个数三者必须相等并且每一个.jpg都能找到同名.xml和同名.txt。我用一段简单脚本核查from pathlib import Path data Path(data) jpgs {p.stem for p in data.glob(*.jpg)} xmls {p.stem for p in data.glob(*.xml)} txts {p.stem for p in data.glob(*.txt)} print(jpg 数量:, len(jpgs)) print(xml 数量:, len(xmls)) print(txt 数量:, len(txts)) print(缺 XML 的图片:, jpgs - xmls) print(缺 TXT 的图片:, jpgs - txts) print(多余标注:, (xmls | txts) - jpgs)正常输出应当是三处差集为空。如果差集不为空训练时 YOLO 只读取有标注的图片数量不对会让验证集评估结果失去可比性。4.2 越界与异常宽高检测labelImg 标注时如果图片边缘被裁切会出现xmax大于图片宽度的情况。YOLO 格式下这类问题表现为归一化坐标大于 1 或者出现负宽高。不检测这些直接训练会让损失函数在初始阶段震荡甚至导致预训练权重被破坏。写一个快速扫描脚本对全部 TXT 做合法性检查import os def check_yolo_txt(txt_path, img_wNone, img_hNone): problems [] with open(txt_path) as f: for line_no, line in enumerate(f, 1): parts line.strip().split() if len(parts) ! 5: problems.append(f第{line_no}行字段数不等于5) continue cid, xc, yc, w, h parts if float(xc) 0 or float(xc) 1: problems.append(f第{line_no}行中心x越界) if float(w) 0: problems.append(f第{line_no}行宽小于等于0) return problems这个脚本没有依赖任何深度学习框架跑一圈能得到所有有问题的标注文件列表。重点查两个方向x_center width/2 1说明框超出右边界y_center - height/2 0说明框超出上边界。出现任何一种都能从同名 XML 里找到原始像素坐标判断是标错了还是本来就在边缘。边缘物体如果只是部分露出可以考虑保留并加一点裁剪但如果是坐标换算错误必须修正后再训。4.3 用 OpenCV 叠加标注框肉眼确认对齐数值检查能做的是找越界但没法发现“框比物体大一圈”这类系统性误差。我每做一个数据集都会抽 20 到 30 张图把标注框叠加回原图上确认对齐程度。目标检测里最怕的不是漏标而是框得不准因为漏标可以通过负样本抑制框不准却会让边框回归的梯度混乱。import cv2 img cv2.imread(data/xyxr_banshou_380.jpg) h, w img.shape[:2] with open(data/xyxr_banshou_380.txt) as f: for line in f: cid, xc, yc, bw, bh map(float, line.strip().split()) 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) cv2.imwrite(visualize_result.jpg, img)这段代码把 YOLO 格式的归一化坐标反算成像素整数再画矩形。如果打印出来的框明显偏离扳手轮廓问题大多出在原始 XML 标注阶段而不是转换过程。多角度目检 20 张以上的结果后如果发现某个方向的扳手大量出现框偏小可以在后续微调时把标注框向外扩几个像素用脚本统一修改 TXT 的宽高值。4.4 单类别数据集的框数与分布观察摘要里写明banshou框数 2097平均每张图约 2 个扳手。训练检测器时单类别且目标稀疏的图像做正样本的效率不高批量大小里的正样本数量少会让梯度更新偏向背景。这种情况下可以把batch适当调大或者开启 mosaic 增强让每个 batch 的样本构成更丰富。另外用小脚本统计存在小目标的图片数量判断是否需要对小目标检测做针对性优化。x_center, y_center, width, height中如果归一化宽度小于 0.1在 640x640 输入下只有不到 64 个像素宽属于小目标范畴此时imgsz建议从 640 提到 768 或 1024否则这类小扳手容易漏检。5. 从扳手数据集延伸单类别权重迁移与小目标检测优化5.1 用预训练模型做两阶段增加召回率训练收敛后yolov8s权重可以当作通用螺丝刀、钳子等工具检测的预训练模型。工业场景里工具类别往往只有几种标注成本不高加载这份扳手数据的训练权重再微调收敛速度会比从 COCO 预训练快很多因为模型已经学会了“细长金属物体”的边缘和纹理特征。yolo detect train datatools.yaml modelruns/detect/train/weights/best.pt epochs50 imgsz640微调时把学习率调低到默认值的 0.5 倍防止对原有特征过度破坏。同时确认tools.yaml的nc与模型头的输出维度匹配如果不匹配YOLOv8 会自动重建检测头但训练速度会略慢。5.2 小目标扳手漏检时先改 imgsz 再谈算法如果训练好的模型在检测小型扳手时召回率偏低我一般是优先把推理和训练分辨率同步提升到 768 或 1024而不是立刻换 YOLOv8 的 P2 输出头。因为 P2 层来自高分辨率特征图带额外计算量小数据集下容易过拟合。先提升imgsz验证效果如果不够再考虑引入切片推理用小图滑动窗口过一遍再合并检测结果。5.3 格式迁移到其它框架的注意点这份数据集的 TXT 是 YOLO 训练格式如果之后要用 MMDetection 或 Detectron2需要转成 COCO 的 JSON。转换时的坑不在于坐标公式而在于每个image的id和annotation的image_id必须对齐。用 TXT 文件名当id唯一键时要先把所有文件排序再统一编号不然 JSON 里会出现悬空引用。标注类别只有一个时COCO 的categories数组长度为 1但category_id仍然从 1 开始算不是 0这是最容易导致训练崩溃的隐藏错误。本文还有配套的精品资源点击获取