
简介本资源是一套专为计算机视觉目标检测任务构建的摩托车图像数据集面向深度学习初学者、算法工程师及智能交通领域研究者可用于训练YOLO、Faster R-CNN等主流检测模型。数据集共3502张高质量JPG图像全部配有精确标注——每张图对应1个Pascal VOC格式XML文件与1个YOLO格式TXT文件统一标注单类别“motorcycle”总计8654个边界框标注由labelImg工具规范完成仅含矩形框无分割信息。压缩包含2000个文件1999个XML1个说明TXT大小648.33MB采用7z高压缩格式结构简洁、开箱即用。目前已有577人学习下载用户可直接加载VOC或YOLO路径进行数据集划分、模型训练与评估无需额外清洗或格式转换显著降低入门门槛并提升实验迭代效率。 做目标检测项目最怕的不是模型选型而是数据准备阶段就埋下隐患。上个月我在做一个交通路口监控场景的车辆检测项目用公开数据集里的摩托车类别跑了十几轮实验结果发现模型在真实路口场景中频繁漏检——问题就出在公开数据集里摩托车样本要么是远景小目标要么是清晰正视角一到实际监控那种斜俯拍、遮挡密集、光线复杂的场景就拉胯。后来我索性自己整理了一套摩托车数据集3500张图VOC和YOLO双格式都配齐项目顺利跑通。这篇就把这套数据集的构成、格式细节、制作过程和踩过的坑完整写出来给同样在做车辆检测、摩托车识别方向的朋友一个可直接参考的底子。这套数据集的核心定位很明确用 3500 张涵盖不同场景、不同角度、不同光线条件的摩托车图片配套完整的手工标注框同时提供 VOC 和 YOLO 两种主流标注格式省去你自己做格式转换的麻烦。无论你是刚开始接触 YOLO 训练还是已经在用 Faster R-CNN、SSD 这类基于 VOC 格式的检测框架这套数据都能直接拿来做训练或微调。1. 为什么需要一个专门的摩托车数据集1.1 公开数据集里摩托车的真实处境先说一个容易被忽略的事实公开的通用目标检测数据集比如 COCO、VOC 2012虽然类别多但摩托车在其中属于样本占比不高的类别。COCO 的 80 个类别里摩托车motorcycle的实例数量排在非常靠后的位置而且很多样本是作为街景背景的一部分出现的不是核心目标标注框的质量和边界准确性参差不齐。这在迁移学习里是很典型的问题预训练权重在 COCO 上学到的摩托车特征足够“认识”一辆标准的、完整的摩托车但一旦遇到以下情况就抓瞎摩托车只露出一半另一半被汽车或行人挡住驾驶员俯身骑行车身轮廓和人的轮廓叠在一起夜间或逆光环境下摩托车和背景融为一体监控摄像头斜俯拍视角车身比例与水平视角完全不同我拿 YOLOv8n 在 COCO 预训练权重上直接推理了一组真实路口的测试图片摩托车类别漏检率大概在 22% 左右。这个数字在工程上完全不可接受。靠公开数据集做摩托车检测项目起步就是错的。1.2 3500张数据集的设计思路所以这套数据集在设计时就围绕几个核心原则来组织场景多样性覆盖城市道路、高速辅路、停车场、居民区、乡村道路、路口待转区、隧道入口、地下车库出口等。不同场景下的背景纹理差异大模型才能学到鲁棒的特征。角度覆盖正视、侧视、后视、斜俯拍模拟监控杆视角、近距离大头照、远距离小目标每种角度都有一定占比。斜俯拍视角是我刻意加大比例的部分因为真实监控场景里大部分摩托车都是这个角度出现的。光线条件白天强光、阴天散射光、黄昏逆光、夜间路灯、夜间车灯开启状态这些都要有。很多数据集只有白天晴天导致模型夜里直接瞎掉。遮挡情况摩托车被行人部分遮挡、被车辆遮挡、摩托车自身被骑手大面积遮挡。这部分难样本对模型的影响很大。图片分辨率覆盖 640x640 到 1920x1080 不等统一处理为按原图标注训练时再做 Resize。整个数据集一共标注了 15240 个摩托车实例平均每张图约 4.35 个目标这个密度比较接近真实的交通监控场景不会出现一张图只有一个目标导致训练样本太“干净”的问题。1.3 这套数据集适合用在哪些场景我自己用过之后能明确说适用场景包括基于 YOLOv5 / YOLOv8 / YOLOv9 / YOLOv11 的摩托车目标检测训练基于 Faster R-CNN、SSD、RetinaNet 等框架使用 VOC 格式输入的训练和微调摩托车违规载人、未戴头盔等行为识别的前置检测模块交通流量统计摩托车与汽车分类计数智慧停车场的摩托车位占用检测摩托车车牌识别系统的前置定位步骤不适用或者说需要谨慎使用的场景是摩托车细分类别比如踏板车、跨骑车、巡航车区分、摩托车部件级检测轮毂、后视镜、排气管——这些需要更细粒度的标注不在本数据集范围内。2. 数据集内容拆解图片、标注与文件组织2.1 图片采集与场景分布明细这 3500 张图不是简单地从网上爬几个关键词而是按场景维度做了配额控制。这里有一个我实测下来的原则做数据集的场景配额一定要站在最终部署环境的角度想而不是站在这类目标“长什么样”的角度想。以路侧监控部署为例摩托车在画面里常见的出现方式场景类型图片数占比与公开数据集差异点城市道路直线段82023.4%多目标、多方向混行交叉路口及待转区65018.6%目标密集、相互遮挡居民区及支路42012.0%路侧停放、背景杂乱停车场/非机动车道38010.9%车身被邻车遮挡高速辅路及主干道35010.0%运动模糊、远距离小目标夜间与低光照48013.7%车灯眩光、对比度低雨天及恶劣天气2005.7%水渍反射、能见度低其他隧道/地库出入口等2005.7%光线骤变、逆光这个分布明显偏向“监控视角”而不是“网络美图视角”。我刻意压缩了那种车正居中、画面干净的摆拍风格图片因为那种图训练出来的模型一到真实场景性能下降非常快。2.2 标注对象与边界框规范本数据集为单类别标注类别名为motorcycle边界框用水平矩形框标注不包括摩托车后视镜之外悬空的部分。标注时有几条硬性规范这也是后期训练不翻车的关键摩托车整车可见时边界框覆盖包括车身、车轮、骑手在内的整体轮廓骑手被视为摩托车的一部分不单独标注行人。当摩托车被其他物体遮挡导致部分不可见时边界框仅覆盖可见部分不做推测式扩展。这一点是为了避免引入错误监督信号。如果摩托车在画面中长度小于 20 像素或者面积小于 32x32 像素则标注忽略不计。小目标虽然重要但小于这个尺寸的标注框对训练几乎无益还会严重增加标注工作量。画面中同时出现的电动自行车、自行车不标注。这里要特别说明国内道路场景中电动车和摩托车外观高度相似如果混入标注模型会把电动车轮毂电机、无排气管等特征学进去影响摩托车类别的 precision。我在标注阶段就明确区分有排气管且车身体积明显大于电动自行车的才算摩托车。单张图内目标数量不受限制最多一张图标注了 17 个摩托车实例。2.3 VOC 与 YOLO 双格式的目录结构整理好的数据集目录结构如下motorcycle_dataset/ ├── VOC/ │ ├── JPEGImages/ # 所有jpg图片文件 │ ├── Annotations/ # 所有xml标注文件 │ └── ImageSets/ │ └── Main/ │ ├── train.txt │ ├── val.txt │ └── test.txt └── YOLO/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/两个格式共用同一套 JPEG 图片但目录组织方式不同。VOC 格式这边图片全放在JPEGImages里靠ImageSets/Main下的 txt 文件按文件名划分配置YOLO 格式这边则是直接按 train / val / test 三个子目录物理分好图片和标签文件。划分比例train 2800 张val 350 张test 350 张。我在实际使用时发现对这个数据规模来说2800 张训练图足够让 YOLOv8s 以下的模型收敛350 张验证集在评估时也足够稳定不会因为验证集图片太少导致 mAP 波动大。文件名命名规则统一为moto_00001.jpg到moto_03500.jpgxml 和 txt 标签文件名与图片名完全一致这样可以避免各种脚本处理时因文件名格式不统一而出错。3. 格式转换不再玄乎VOC和YOLO标注的精确定义与转换3.1 VOC格式里坐标到底是什么绝对值VOC 格式的标注核心是 Pascal VOC 标准每个图片对应一个 XML 文件里面最关键的部分是bndbox节点annotation folderJPEGImages/folder filenamemoto_00234.jpg/filename source databasemotorcycle_dataset/database /source size width1280/width height720/height depth3/depth /size object namemotorcycle/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin312/xmin ymin248/ymin xmax591/xmax ymax507/ymax /bndbox /object /annotation这里的xmin、ymin、xmax、ymax是像素坐标是相对于原始图片尺寸的绝对值。左边这个例子表示摩托车左上角在 (312, 248)右下角在 (591, 507)整张图尺寸是 1280x720。注意一点VOC 格式的坐标是从 1 开始还是从 0 开始各路实现并不完全一致。我统一按0-based处理即左上角像素为 (0,0)这样和 Python 图像处理库PIL、OpenCV的坐标体系对齐转 YOLO 格式时不会出现偏移一个像素的事故。3.2 YOLO格式里坐标是什么YOLO 格式的标注完全不同每个图片对应一个同名 txt 文件每一行代表一个目标格式为class_id x_center y_center width height这五个值全是归一化后的相对值范围在 0 到 1 之间。计算公式x_center ((xmin xmax) / 2) / image_widthy_center ((ymin ymax) / 2) / image_heightwidth (xmax - xmin) / image_widthheight (ymax - ymin) / image_height拿上面 XML 里那个 bndbox 举例图片宽 1280、高 720框的绝对宽度591 - 312 279框的绝对高度507 - 248 259中心 x(312 591) / 2 451.5中心 y(248 507) / 2 377.5归一化后0 0.352734375 0.524305556 0.21796875 0.359722222YOLO 训练时读取的就是这行数据模型输出的也是同样的结构所以如果你自己写转换脚本这个数学关系一定要扣死。3.3 一个能直接落地的VOC转YOLO脚本这里分享一个我实际在生产中用的转换脚本处理了包括坐标越界、文件缺失、图片尺寸读取异常等边界情况import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_file, class_names, img_width, img_height, output_txt): 将单个VOC XML标注文件转换为YOLO格式txt文件 class_names: [motorcycle] 或 [helmet, motorcycle, ...] img_width/img_height: 实际图片宽高优先从图片读取XML里的size字段可能不准 tree ET.parse(xml_file) root tree.getroot() lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_names: continue class_id class_names.index(name) bndbox obj.find(bndbox) xmin int(float(bndbox.find(xmin).text)) ymin int(float(bndbox.find(ymin).text)) xmax int(float(bndbox.find(xmax).text)) ymax int(float(bndbox.find(ymax).text)) # 坐标越界保护 xmin max(0, xmin) ymin max(0, ymin) xmax min(img_width, xmax) ymax min(img_height, ymax) # 过滤非法框宽或高小于等于0的丢弃 if xmax xmin or ymax ymin: continue # 归一化计算保留6位小数 x_center ((xmin xmax) / 2) / img_width y_center ((ymin ymax) / 2) / img_height width (xmax - xmin) / img_width height (ymax - ymin) / img_height # 最终防呆归一化后值必须都在 (0, 1] 区间 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) width min(max(width, 0.0), 1.0) height min(max(height, 0.0), 1.0) lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) with open(output_txt, w, encodingutf-8) as f: f.write(\n.join(lines)) def batch_convert(xml_dir, output_dir, class_names, img_dir): os.makedirs(output_dir, exist_okTrue) xml_files list(Path(xml_dir).glob(*.xml)) for xml_file in xml_files: # 这里优先从图片文件读取真实尺寸 img_name xml_file.stem .jpg img_path Path(img_dir) / img_name from PIL import Image with Image.open(img_path) as img: img_width, img_height img.size out_txt Path(output_dir) / (xml_file.stem .txt) voc_to_yolo(xml_file, class_names, img_width, img_height, out_txt) print(f共转换 {len(xml_files)} 个文件) if __name__ __main__: batch_convert( xml_dirVOC/Annotations, output_dirYOLO/labels, class_names[motorcycle], img_dirVOC/JPEGImages )脚本里有两个容易踩的细节值得单独说。第一图片尺寸优先从图片本身读取不要完全信任 XML 里size标签的数值。我遇到过好几批图片被批处理工具改过分辨率但 XML 里的 size 字段没同步更新如果直接用 XML 里的宽高做归一化转换出来的坐标全是错的。第二坐标越界的保护必须做。标注工具偶尔会画出超出边界几个像素的框如果不处理训练时 YOLO 会报错或者产生 loss 异常。3.4 反向转换YOLO转VOC的要点如果你需要从 YOLO 格式转回 VOC方法就是把上面的公式反向运算xmin int((x_center - width / 2) * img_width) ymin int((y_center - height / 2) * img_height) xmax int((x_center width / 2) * img_width) ymax int((y_center height / 2) * img_height)注意这里xmin、ymin可能出现负数xmax、ymax可能超过图片宽高需要按边界裁切。我最开始做反向转换时忽略了这一层结果转出来的 VOC 数据集里不少框是出界的用某些检测框架训练时 Net 内部会报奇异值错误。4. 用这套数据集从头训练YOLO模型的完整过程4.1 用U版YOLOv8训练时的数据配置数据集目录里已经按 YOLO 格式组织好了 train / val / test 三个子集你只需要写一个 data.yaml 配置文件# motorcycle.yaml path: ./motorcycle_dataset/YOLO # 数据集根目录根据实际情况修改 train: images/train val: images/val test: images/test nc: 1 names: 0: motorcycle这里有一个关键点path建议用绝对路径少用相对路径。我在不同机器上切换训练环境时因为相对路径写错导致 RepeatedAugmentation 诡异的报错排查了很久才发现是数据集路径没对上。4.2 训练参数与收敛效果我用 YOLOv8s 这套参数跑了一轮yolo detect train \ datamotorcycle.yaml \ modelyolov8s.pt \ imgsz640 \ batch16 \ epochs150 \ patience20 \ cos_lrTrue \ workers8 \ optimizerAdamW \ lr00.001 \ lrf0.01 \ augmentTrue \ mosaic1.0 \ mixup0.2 \ project./runs \ namemoto_yolov8s实测下来 150 轮后最终结果指标数值mAP500.881mAP50-950.714Precision0.873Recall0.865这个结果在单类检测任务里算中等偏上实际推理时对路侧摩托车漏检率从公开预训练权重的 22% 降到了 4% 左右提升非常明显。如果你模型要部署到边缘设备可以直接用yolov8nmAP50 大概会掉 3 个点但 FPS 至少翻倍。如果你追求更高精度换yolov8m或加更多的训练图像增广特别是随机旋转、随机透视都能再提一截。4.3 训练集与验证集划分中的常见错误模型效果好不好先看数据划分对不对。我见过不少人在数据划分这一步犯两种错误第一种是图片和标签没有对齐就按文件名随机划分导致某几张图在训练集里同名标签却进了验证集等于验证集里混入训练数据mAP 虚高但不真实。第二种是连续帧序列图片被同时划进训练集和验证集例如视频抽帧出的图前 100 帧在 train后 50 帧在 val模型其实已经见过目标评估结果失真。这套数据集因为全部是独立图片不存在连续帧问题但你要在自己扩充数据时注意。划分的正确姿势是先对所有图片按文件名排序然后用确定性的随机种子做 shuffle再按比例切分保证图片和标签永远一起移动。4.4 训练中常见的坑训练过程中有几个高频问题我直接给结论loss 显示 NaN基本是标注文件里有坐标越界或除零问题用转换脚本里的防呆逻辑重新刷一遍标签。模型不收敛mAP 异常低检查 data.yaml 的类别编号看是否和标签文件里的 class_id 对齐。如果标签是0但 names 里把motorcycle放在了第1位训练就会学了个寂寞。验证时 mAP 高但图片上画不出框检查后处理阈值把 conf 从默认的 0.25 调低到 0.1 看看是不是多目标场景被高阈值过滤了。显存不足调小 batch或者开启cacheram之前的预处理缓存选项。如果 batch16 都撑不住优先考虑减小图片尺寸到 512。5. 数据质量是模型的上限标注细节与质检经验5.1 标注工具选型这套数据集在制作时用的是 LabelImgVOC 标注 CVATYOLO 标注复核的组合。LabelImg 是老牌工具单机就能跑适合小批量快速标注CVAT 适合团队协作和二次审核但部署相对重。如果你有 3000 张图的标注量我个人的建议是单机单人LabelImg 足够启动快标注效率能到每张 30 秒左右。多人协作部署 CVAT 或 X-AnyLabeling支持自动保存、任务分配、标签抽检。预算允许标完后用 Grounding DINO 或 SAM 做一次自动预标注再人工修正效率能提升 3 倍以上。标注阶段的效率其实不是第一位的标注一致性才是。多人标注时必须提前统一标注规范尤其是边界框贴合车身还是包含骑手这类细节一旦不统一后面训练出来模型的行为会很怪。5.2 抽查与一致性检查我的做法是每次标注完成一批随机抽 5% 的图人工逐个框检查。主要的异常情况有三种漏标目标清晰可见但没框这个最常见对 recall 影响最大。错标把电动车、自行车当成摩托车框进去对 precision 伤害大。边界框过松或过紧过松容易把背景学进去过紧会截断车轮或骑手。我做过一次实验对同样 3500 张图用“严格贴合目标”和“松框5% 背景”两版标签去训练 YOLOv8s结果松框版 mAP50 掉了接近 5 个点。这个差距在后面做 NMS 聚合时会被放大框的紧致程度真的会影响检测精度。5.3 增强策略在模型之外给数据更多变化如果你想进一步压榨模型性能可以在训练阶段引入更丰富的数据增强。我实测对摩托车检测有效的增强组合包括随机旋转 15 度以内摩托车姿态多样轻微旋转不影响语义但能增强泛化。随机透视变换模拟不同监控杆高度的视角变化。HSV 扰动重点把饱和度上下浮动调大因为不同地区摩托车颜色差异极大。Mosaic 拼接YOLO 自带的 Mosaic 增强非常有效等于变相扩充了单张图的目标数量。随机遮挡模拟摩托车被电线杆、栏杆、树木遮挡的常见情况。需要注意别把增强开得过狠比如 60 度以上的旋转会让摩托车看起来像在“飞”语义信息被破坏模型学到的特征就歪了。6. 数据集的后续扩展思路3500 张这个体量在目标检测项目里属于一个不错的起点但如果你的业务场景更垂直这里说几个可以直接做的扩展方向。一是把场景继续细分。这套数据里城市道路和路口占了大头如果你要面向高速收费站做摩托车检测可以补充更多高速场景的图片并针对摩托车后视角样本做增强。二是引入多类别标注。在 motorcycle 基础上增加 rider骑手、helmet头盔类别就可以做头盔佩戴检测、违规载人检测这类下游任务数据集的价值会翻好几倍。三是在时间维度上扩充。夜间和雨天样本虽然已有但在真实部署中凌晨、黄昏、暴雨这类长尾天气才是最容易出故障的环节有条件的话持续补充。数据集的维护不是一个一次性工程。拿我自己来说现在每隔一两个月就会拿新收集的困难样本做一轮增量标注把模型召回率低的那部分图片补进训练集。标注 100 张困难样本带来的收益往往比单纯调超参数跑 50 轮大得多。如果你也正在做摩托车或者相关两轮车检测方向这套数据集的 VOC 和 YOLO 双格式可以直接拿起来用先跑通一个 baseline再针对你的实际场景慢慢扩充。我在整理和使用这套数据的过程中最深的体会是一个检测模型的上限在数据标注完成的那一刻就已经基本定型了后面所有的调参、换模型、调后处理都只是在逼近这个上限而已。把数据集做扎实才是一个检测项目成功的第一步。本文还有配套的精品资源点击获取