尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于YOLOv8的摩托车与行人目标检测数据集实战解析

基于YOLOv8的摩托车与行人目标检测数据集实战解析 简介摩托车与行人目标检测数据集是一份面向道路监控与智能交通场景的工业级标注数据专为需要开展目标检测算法训练与验证的开发者、研究人员设计。压缩包共2000个文件核心包含1095个txt标签文件、903张jpg道路场景图片、1个yaml类别配置及1个docx说明文档整体大小约62.91MB。资源聚焦摩托车和行人两类关键目标采用YOLO格式的归一化边界框标注可支撑交通流量统计、危险行为预警、自动驾驶感知增强、智慧城市安防及人车互动行为研究等任务兼容YOLOv5/v7/v8等主流检测框架开箱即用。数据集具有目标定位精准、场景针对性强等优势标签与图像一一对应yaml配置便于直接修改类别docx文档说明了数据组织方式能够大幅降低上手门槛。目前已有124人学习下载数据覆盖多种光照和视角条件可帮助使用者在真实道路场景上快速构建检测模型、评估算法泛化能力从而节省大量数据采集与标注时间。1. 摩托车与行人目标检测数据集从路测监控到YOLO训练样本的拆解如果你拿到一个.zip压缩包里面是1095张道路监控JPEG图和对应的YOLO格式txt标签类别只有motorcycle和pedestrian两个第一反应是什么我通常会先看标注文件和图片是否对得上再决定能不能直接丢进YOLOv8训练。这个摩托车与行人目标检测数据集就是这样的结构训练集937张、验证集158张全部来自实际道路监控场景覆盖不同光照和视角。对于做交通监控、自动驾驶感知验证或者智慧城市安防的团队来说它解决了冷启动时“没有现成标注数据”的问题。更重要的是因为格式标准它可以和COCO2017数据集结构里的类别映射做对照快速迁移到自己的任务上。下面从数据格式、训练配置到推理验证完整过一遍。2. 数据与标注YOLO格式下的摩托车/行人样本构成这个数据集从文件命名就能看出是Roboflow导出的格式image-572-_jpg.rf.49ecbc...jpg每张图对应一个同名.txt标签。解压后第一件事是用tree命令确认目录层级常见做法是不管zip包里面怎么嵌套先平铺到一个datasets根目录下让图片和标签一一对应。zip包本身不需要额外处理用unzip解压后就能直接看到训练集和验证集的图片、标签目录。2.1 训练/验证划分与场景覆盖观察数据总量是1095张训练集937张、验证集158张分割比例大约85.5%和14.5%。这个比例对两类目标检测任务来说够用但要注意验证集图片和训练集如果来自同一段监控视频的不同帧会存在一定程度的相似性导致验证精度虚高。我一般会抽查验证集里是否有过分接近的连续帧方法很简单把验证集图片的感知哈希算出来两两对比汉明距离。import os import imagehash from PIL import Image import itertools val_dir datasets/val/images hashes {} for fname in os.listdir(val_dir): if fname.endswith(.jpg): hashes[fname] imagehash.phash(Image.open(os.path.join(val_dir, fname))) for (f1, h1), (f2, h2) in itertools.combinations(hashes.items(), 2): if h1 - h2 5: print(f疑似重复: {f1} - {f2}, 汉明距离 {h1-h2})这段代码用imagehash库计算感知哈希汉明距离小于5通常意味着两张图视觉上非常接近。跑完后如果发现大量重复帧建议重新划分验证集否则后面跑出的mAP参考价值要打折扣。场景覆盖方面图片来自道路监控视角偏高位车身和行人存在不同程度的遮挡这对训练前的数据清洗提出了要求。从图片尺寸来看实际监控画面通常是1920x1080或1280x720但YOLO标签的坐标已经归一化所以无论原始分辨率是多少读取时都能统一缩放到训练尺寸。这个数据集里没有提供exif信息不过从JPEG文件头可以读取宽高。我建议用下面的命令统计一下所有图片分辨率确认是否存在混合分辨率。python -c from PIL import Image import os, collections sizes collections.Counter() for split in [train,val]: for f in os.listdir(fdatasets/{split}/images): with Image.open(fdatasets/{split}/images/{f}) as im: sizes[im.size] 1 print(sizes) 如果发现大部分图片是同一分辨率说明数据来源一致训练时不容易出现尺度跳动。如果混合了多个分辨率需要设置合理的imgsz训练参数否则宽幅画面中的摩托车会被压缩成小目标。2.2 边界框标签格式与统计方法标签是标准的YOLO格式每行内容为class x_center y_center width height所有坐标均归一化到0~1。在目标检测算法里这种格式是绕不开的基础。类别0对应motorcycle类别1对应pedestrian。我打开其中一个标签文件内容类似0 0.421875 0.639815 0.104167 0.162500 1 0.710938 0.653241 0.089583 0.225000第一行表示一个摩托车目标中心点在图片的相对位置(0.42, 0.64)宽高占图幅的10.4%和16.3%。第二行是一个行人。注意这里没有单独的类别文件类别映射通常是数据集描述里给出的。如果你还要复用到其他框架建议先写一个classes.txt内容是两行类别名后面转COCO或VOC格式会更快。为了验证所有标签是否合法我习惯跑一段快速检查脚本python -c import os for split in [train,val]: for f in os.listdir(fdatasets/{split}/labels): with open(fdatasets/{split}/labels/{f}) as fp: for line in fp: parts line.strip().split() assert len(parts) 5, f非法标签行: {f} {line} x, y, w, h map(float, parts[1:]) assert 0 x 1 and 0 y 1 and w 0 and h 0, f坐标越界: {f} {line} print(标签格式全部通过) 这个逻辑就是把每行拆成5个字段检查类别ID是否在0或1中心坐标是否在[0,1]区间宽高是否为正。如果出现w或h为0多半是标注工具的退化框训练时会被当成背景直接跳过或删除该行。进一步统计框的尺寸和类别分布有助于判断模型容量和分辨率选择。下面这段代码统计每个类别框的面积占整图比例import os import numpy as np areas {motorcycle: [], pedestrian: []} counts {motorcycle: 0, pedestrian: 0} for split in [train, val]: label_dir fdatasets/{split}/labels for f in os.listdir(label_dir): with open(os.path.join(label_dir, f)) as fp: for line in fp: c, x, y, w, h line.split() name motorcycle if int(c) 0 else pedestrian counts[name] 1 areas[name].append(float(w) * float(h)) for name in counts: arr np.array(areas[name]) print(f{name}: 样本数 {counts[name]}, 面积中位数 {np.median(arr):.4f}, 90分位 {np.percentile(arr, 90):.4f})通过面积分布可以看出小目标占比。如果大量框的面积小于0.01也就是框的宽高各不到原图的10%那在640分辨率下可能只有30x30像素左右需要适当提高输入分辨率或使用小目标检测模块。2.3 标注可视化与质量问题处理机器检查只能发现格式错误标注偏移和类别错标还需要人工抽查。我一般会写一个OpenCV可视化脚本把标注框画到图上生成一张拼图快速扫一遍。脚本代码如下import cv2 import os def draw_boxes(image_path, label_path, out_path): img cv2.imread(image_path) h, w img.shape[:2] with open(label_path) as f: for line in f: c, x, y, bw, bh map(float, line.split()) x1, y1, x2, y2 ( int((x - bw / 2) * w), int((y - bh / 2) * h), int((x bw / 2) * w), int((y bh / 2) * h), ) color (0, 255, 0) if int(c) 0 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, motorcycle if int(c)0 else pedestrian, (x1, max(0, y1 - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1) cv2.imwrite(out_path, img) for split in [train, val]: img_dir fdatasets/{split}/images lbl_dir fdatasets/{split}/labels os.makedirs(fvisual_{split}, exist_okTrue) for f in os.listdir(img_dir): if f.endswith(.jpg): stem f.replace(.jpg, ) if os.path.exists(os.path.join(lbl_dir, stem .txt)): draw_boxes(os.path.join(img_dir, f), os.path.join(lbl_dir, stem .txt), fvisual_{split}/{stem}.jpg)这段代码会把每个框按类别画成绿色或红色保存到visual_train和visual_val目录。肉眼扫一遍重点看两类问题一是标注框是否刚好框住目标有没有把背景大片包含进来二是摩托车和行人同时出现时标注框是否重叠得不符合逻辑。如果发现部分边界框明显偏移可以用LabelImg或Roboflow重新修正但考虑到数据集来自实际道路监控标注整体质量在线少量偏差在可接受范围内。下面表格汇总了我在校验过程中遇到过的问题和处理方式问题类型症状处理方式标签缺失图片存在但txt不存在丢弃该图或重跑标注文件重名不同目录下同名统一重命名前缀加split类别ID错误行人标成0逐个检查类别文件框退化width/height为0删除对应行框严重偏移框中心不在目标上人工修正或作为困难样本保留这一层校验做完才进入训练环节。不同框架对目录要求略有差别但YOLOv8的train和val目录结构是固定的下一章就按这个结构配置。3. 基于YOLOv8的训练配置与参数调优拿到标注数据后选型不是越新的模型越好。摩托车和行人两类目标在道路监控里尺度差异大行人不时被摩托车遮挡所以需要兼顾小目标召回率和推理速度。YOLOv8系列中我一般用yolov8s或yolov8m既能满足实时性又能通过数据增强弥补样本量不足。如果你的目标是快速验证yolov8n也行但后面调参时容易碰到容量瓶颈。3.1 数据集目录组织与data.yaml把zip解压后重排成标准目录datasets/ ├── train/ │ ├── images/ │ └── labels/ ├── val/ │ ├── images/ │ └── labels/ └── data.yamldata.yaml内容如下path: /absolute/path/to/datasets train: train/images val: val/images nc: 2 names: 0: motorcycle 1: pedestrian注意path字段在YOLOv8里必须是绝对路径或相对ultralytics运行目录的路径。踩过坑是写成相对路径后训练时找不到图片最后统一改成绝对路径才正常。nc必须等于2和names中的类别数一致。如果你准备把该数据集与COCO2017数据集结构里的其他类混合训练需要把names扩充并重新映射类别ID但那样要重新生成标签不建议在初期做。3.2 训练命令和模型选型命令行启动训练yolo detect train \ datadata.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ augmentTrue \ patience20参数含义如下参数作用建议值model预训练权重yolov8s.ptepochs训练轮数100样本少可以早停imgsz输入分辨率640兼顾监控场景batch批量大小按显存调整16或32lr0初始学习率0.01小数据集可降到0.005patience早停轮数20防止过拟合我一般会先跑50轮观察损失曲线。如果val/box_loss在30轮后不再下降就把patience调小节省时间。显存不足时最有效的手段是降低batch到8而不是盲目缩小imgsz因为输入分辨率对监控小目标检测影响很大。如果batch降到4还不够可以使用梯度累积YOLO命令行没有直接暴露该参数但可以在Python训练脚本中设置accumulate参数。YOLOv8不同尺寸模型的选择参考模型推理速度小目标检出能力适用场景yolov8n最快较弱边缘盒子实时监控yolov8s快中等主流服务器通用项目yolov8m中等较强精度优先延迟容忍如果你后面的任务是交通流统计需要长时间跑视频流yolov8s是性价比最高的。yolov8n在牌照级远处行人上容易漏检yolov8m在1080p视频上仍能跑到30fps以上但对显卡要求更高。3.3 数据增强与类别不平衡处理这个数据集里摩托车和行人的数量并不完全平衡监控场景中行人出现的频率可能更高。YOLOv8自带增强策略马赛克、翻转、HSV扰动等对小数据集通常有正面效果。我建议开启augmentTrue但如果发现训练集和验证集分布差异大马赛克增强会在最后10轮关闭因为马赛克会拼接多张图导致目标尺度失真。YOLOv8内部已做这种调度不需要手动干预。如果类别不平衡严重例如行人样本是摩托车的两倍以上需要调整损失权重。YOLOv8没有直接暴露类别权重参数常见做法是复制少样本的标签行或者用cls损失系数。我用过最简单的方法是先训练一版统计验证集上各类别的recall再针对低召回类别补充裁剪样本。数据集本身标注质量不错一般不需要过度处理。对这类小数据集冻结预训练backbone的前几层可以加速收敛也能防止过拟合。命令里加一个freeze10即可yolo detect train \ datadata.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ freeze10freeze10表示冻结模型前10层这些层提取的纹理、边缘特征在ImageNet和COCO上已经学得很充分不需要在少量交通数据上重新学习。后面层仍然会更新用于学习摩托车和行人的组合特征。经验上冻结前10层能缩短约20%的训练时间对最终精度影响很小。训练结束后runs/detect/train/目录下会生成weights/best.pt和last.pt以及results.png曲线。下一步就是加载best.pt做实际推理验证。这里特别提醒验证集表现不等于监控视频表现必须拿一段没见过的视频来测试。下一章专门讲推理与评估。4. 实战在自有监控视频上验证模型效果训练完只看mAP是不够的。交通监控场景里摩托车和行人的姿态变化大摄像头角度固定但光照变化剧烈。我习惯的做法是用模型跑一段真实监控视频逐帧保存结果然后人工扫一遍重点看漏检和误检。4.1 加载best.pt进行推理先用best.pt跑单张图片验证from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict( sourcetest_images/, conf0.25, iou0.5, saveTrue, save_txtTrue, )source可以是图片目录也可以直接给视频文件路径。conf是置信度阈值监控场景建议设0.3以上否则误检会增多iou是NMS的IoU阈值默认0.5。输出会保存在runs/detect/predict/下save_txt会生成YOLO格式的检测结果方便后续做统计。对于视频文件model.predict会自动逐帧推理并输出注释后的视频但实际项目里我更常直接用cap cv2.VideoCapture读帧并处理这样能把检测结果和业务逻辑直接接起来。示例代码import cv2 from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) cap cv2.VideoCapture(traffic.mp4) fps cap.get(cv2.CAP_PROP_FPS) width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) writer cv2.VideoWriter(output.mp4, cv2.VideoWriter_fourcc(*mp4v), fps, (width, height)) while cap.isOpened(): ret, frame cap.read() if not ret: break results model.predict(frame, conf0.3, verboseFalse) annotated results[0].plot() writer.write(annotated) cap.release() writer.release()这里results[0].plot()会把检测框、类别和置信度直接画在帧上省去手工绘制的麻烦。如果要在低成本设备上运行可以关闭verboseFalse减少终端打印开销。4.2 评估指标、混淆矩阵与失败样本YOLOv8训练结束后可以用val模式直接评估yolo detect val datadata.yaml modelruns/detect/train/weights/best.pt这一步会输出每个类别的mAP50、mAP50-95、precision、recall。如果是二类数据集重点看行人类别的recall因为行人是弱势交通参与者漏检的后果比误检严重。尤其要注意小目标监控画面中远处的行人往往低于32x32像素在YOLOv8的检测头中可能被判为背景。对于这种场景建议把imgsz从640提到960或者使用SAHI等切片推理库。常见做法是把原图切成若干重叠图块分别推理后合并。混淆矩阵是分析错误来源的关键。训练结束后在runs/detect/train/confusion_matrix.png中可以看到类别间的混叠情况。我根据实际经验列举一个典型的混淆矩阵真实\预测motorcyclepedestrian背景motorcycle9046pedestrian88012背景350从这个表里可以看到摩托车的召回率约90%行人约80%。行人被漏检到背景的12%通常是远处小目标或被摩托车遮挡的瞬间。摩托车被误检成行人的4%多数是骑车人下车推行时的姿态。这种混淆信息比单一mAP值更有用它直接告诉你该补哪些数据。4.3 小目标、夜间与遮挡场景的针对性优化摩托车和行人互相遮挡是监控场景的常态。我遇到过的问题是摩托车驾驶人被判定为行人原因是标注时把人车合并在一个框里。此时需要回到标注层面检查如果边界框同时覆盖了摩托车和骑车人模型学到的特征就会混淆。这个数据集在标注时对摩托车和行人分别画框但监控视角下骑车人身体和摩托车高度重叠模型容易只检测出摩托车。解决方法是训练后对检测结果做后处理用包围框面积比例和历史帧速度来辅助分类或者把骑车人单列第三类。但单列第三类需要额外标注数据量不够时效果反而差。夜间场景的曝光不足会显著降低召回。YOLOv8不支持自动对比度增强需要在外接的预处理里做CLAHE。下面这段代码用于推理前增强import cv2 def preprocess(frame): lab cv2.cvtColor(frame, cv2.COLOR_BGR2LAB) l, a, b cv2.split(lab) l cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)).apply(l) return cv2.cvtColor(cv2.merge([l, a, b]), cv2.COLOR_LAB2BGR)把preprocess应用在每一帧后再送入模型可以提升夜间小目标召回。代价是推理帧率下降约15%。如果部署在边缘设备上建议只对低照度帧启用。判断标准很简单计算灰度图均值如果小于80就启用增强。对于更小目标还可以把输入图切成四块分别推理再合并结果。这种切片方式会显著增加计算量但漏检率下降明显。实际项目中我会优先保证视频流实时性切片只在报警区域中使用比如对道路远端区域做局部放大检测。5. 进阶把摩托车/行人检测接到交通流统计与预警模型能出检测框只完成了第一步实际项目里还要做目标追踪、事件判定和性能优化。这里我给出一个可以落地的组合方案YOLOv8 ByteTrack 规则引擎。5.1 目标追踪与跨帧ID关联监控视频中摩托车和行人移动会出现短暂遮挡ByteTrack相比DeepSORT不需要外观特征在小目标场景下更稳定。用ultralytics内置的track方法results model.track(sourcetraffic.mp4, trackerbytetrack.yaml, persistTrue)这会输出每个目标的track_id同一目标在不同帧中保持相同ID。有了ID就能统计进入画面的目标数量。注意固定摄像头场景中背景静止可以使用帧差法过滤掉静止目标只统计运动的摩托车和行人。ByteTrack的默认配置中track_buffer是30帧match_thresh是0.8。如果视频帧率是25fps那么目标被遮挡1.2秒以内仍然能保持ID超过就会重新分配。对交通监控来说这个参数够用如果路口拥堵导致目标停滞可以适当增大track_buffer到50。5.2 越线与聚集事件的规则实现例如判断摩托车是否越过停止线可以采用逻辑取摩托车检测框底边中点坐标当该点跨越预设的ROI线时触发事件。落地代码片段prev_y {} line_y 500 for frame_id, result in enumerate(frame_results): for box in result.boxes: x1, y1, x2, y2 map(int, box.xyxy[0]) track_id int(box.id) category int(box.cls) if category 0: current_y (y1 y2) // 2 if track_id in prev_y and prev_y[track_id] line_y current_y: print(f摩托车 {track_id} 在帧 {frame_id} 越过停止线) prev_y[track_id] current_y这里line_y是ROI线的纵坐标prev_y保存每个目标上一帧的底边中点。当上一帧在线上方、当前帧在线下方时判定为一次越线。注意要加一个去重逻辑防止同一目标连续多帧触发。行人聚集检测可以通过统计单位面积内行人框中心点密度实现。当密度超过阈值且持续时间超过5秒触发预警。具体做法是维护一个滑动窗口队列每帧统计人数如果连续超过10帧且框中心点两两距离小于100像素的数量超过5个就发出预警。实际调参时要结合摄像头安装高度和视角。5.3 部署优化TensorRT与半精度推理最后是性能。TensorRT加速是最常用方案YOLOv8导出yolo export modelbest.pt formatengine device0导出的engine文件在Jetson等嵌入式设备上可以用。如果对延迟敏感开启半精度FP16通常在保证精度前提下提速1.5~2倍。另一个优化点是降低推理分辨率但监控小目标多不宜降到480以下。在公开数据集上可能看不出差异但在实际道路上小目标漏检率会直线上升。验证部署效果时建议准备一份包含白天、夜晚、雨天三个场景的测试视频统计每类目标的precision和recall。这个摩托车与行人目标检测数据集覆盖了多种光照和视角作为训练起点够用但要让自己模型的泛化能力真正上线还要在实际环境中持续补充困难样本。比如把夜间误检的灯影、雨天地面反光这些false positive单独收集起来定期融入到训练集里重训模型才会越用越稳。本文还有配套的精品资源点击获取
返回列表