资讯动态

航拍校园操场人体检测数据集制作全流程与踩坑指南

发布时间:2026/9/29 19:56:44 来源:尧图企业网站定制
1. 无人机俯拍视角下的人体检测到底难在哪收到一个航拍校园操场人体检测数据集的制作需求时我一开始是有点轻视的心想人体检测嘛成熟方案一大把YOLO跑起来不就行了真正把无人机飞到操场上方拿回第一批原始素材开始处理我才意识到问题没那么简单。网上下载的通用人体检测模型在平视镜头下效果不错但当画面变成约90度垂直俯拍时最常见的表现是漏检严重——楼顶、操场、跑道上的人全都变成了一个个小色块模型几乎没有反应。这才是航拍人体检测这个方向真正需要专门数据集的原因。1.1 俯拍视角带来的目标尺度问题比想象中严峻先交代一个核心概念地面采样距离GSDGround Sample Distance。GSD可以理解为照片中一个像素对应地面多大尺寸。假设你使用一台2000万像素的相机在60米高度以约60度云台俯角拍摄操场GSD通常在2到4厘米每像素之间也就是说一个身高170厘米的成年人在画面中可能只有大约50到70像素高。看起来似乎不算太小但如果你用YOLO默认的640输入尺寸训练在展开的操场全景图里一个班四五十个学生分散在几个篮球场大小的区域单个人体的像素尺寸会迅速缩水到15到30像素之间。物体越小特征越少模型能依赖的局部细节就越有限这是航拍人体检测漏检率高的直接原因之一。更麻烦的是透视形变。平视视角下人体呈现明显的“头身”比例结构模型容易学习躯干、四肢的空间关系。但垂直俯拍时模型看到的更多是头顶、肩部以及地面投影轮廓。学过目标检测的人应该都清楚模型对特征的提取依赖训练数据中的模式如果训练集里全是平视人体它根本没有机会建立“头顶加肩部轮廓等于人”这类俯拍特征。这也是为什么直接用COCO或CrowdHuman预训练权重去跑航拍图效果往往很不理想。1.2 通用人体检测数据集为什么在操场场景会失效我们来做一个简单对比。COCO数据集中的人体大多来自自然图像通常是完整站立或者行走的姿态而且人占画面比例相对较大。CrowdHuman虽然解决了密集人群的问题但依然是街道场景、平视视角。校园操场的特点是大面积单一底色绿色草坪、红色跑道人体排列相对整齐课间操队形、体育课分组且经常伴随明显的阴影干扰。这些特征在通用数据集中非常少见。模型在通用数据上表现良好并不能证明它能适应大面积同色背景下的俯拍小目标检测。你真正需要的是一个贴近航拍视角、包含足球场、跑道、篮球场、中间草坪等多种操场子场景的数据集。这个数据集要解决的就是“上帝视角”下的密集小目标人体检测问题——包括课间操的全校学生聚集、体育课的分组活动、运动会上沿跑道分布的观众和运动员。只要你想通过无人机实现校园操场人流统计、体育教学过程中的学生安全看护、异常滞留检测这类数据就是模型落地的基础。如果你想复现整个流程这篇博客的思路和踩坑记录可以直接拿来参考。2. 数据采集参数设置、抽帧筛选与切片预处理数据集的源头是原始航拍素材素材质量直接决定标注效率和模型上限。很多人在这一步偷懒随便飞一段视频就抽帧结果画面模糊、曝光不均后面全是在为采集阶段的粗糙买单。我的做法是提前规划拍摄参数和飞行路线把原始素材当成“半成品数据”来对待。2.1 飞行高度、云台角度与光照时段的确定以我使用的设备为例一架四旋翼无人机搭载1英寸传感器相机有效像素约2000万。为了覆盖整个操场同时保证人体清晰我选择的飞行高度是40到100米区间。高度越低人体像素越大但单张覆盖范围小采集效率低高度越高覆盖范围大但人体辨识度下降。经过几轮测试综合平衡后我把常规拍摄高度定在60到80米。云台角度上纯90度垂直俯拍获取的地面透视最规整但人脸和头部特征几乎完全不可见部分姿态下人体轮廓会和地面阴影融合。我采用的是60到75度之间的倾斜俯拍既能保留一定的人体侧面特征又不会让目标因为透视关系产生过大的形变。需要特别提醒的是同一批数据集最好固定在一个高度区间内采集因为YOLO模型对尺度变化虽然有一定鲁棒性但训练数据中如果高度跨度太大容易导致模型在中间高度区间出现性能抖动也就是常见的尺度敏感问题。光照时段我选择晴天上午9到11点以及下午3到5点这两个时间段太阳高度适中人体在地面的投影较短不会大面积干扰目标轮廓识别。阴天虽然光线均匀但人体与草坪、跑道的对比度下降标注时连人眼都不容易分辨边界更别说模型了。在保证安全且符合相关管理规定的前提下实际操作中我也用软件对原始素材做了人脸区域的模糊脱敏处理确保数据集不涉及个人隐私。2.2 视频抽帧与模糊帧清理原始视频采用4K 30帧录制数据量不小。连续视频帧之间的内容重叠度太高全部抽出来只会让标注工作变得极其低效而且相邻帧的相似样本会让模型在训练时反复看到近乎相同的目标导致过拟合。我的抽帧策略是每隔30帧取一帧相当于每秒选取1张画面。如果你希望数据量更大可以适当提高抽帧频率但一般来说每秒1到2张已经足够。抽出来的帧中很大一部分会因为无人机悬停不稳、运动模糊、对焦延迟而发虚。我写了一段简单的清晰度筛选脚本使用OpenCV拉普拉斯算子计算图像方差低于预设阈值的帧直接淘汰。阈值我根据历史经验放在约120到180之间具体数值和图像分辨率相关你在实际操作中可以先用十几张图做测试找出清晰与模糊之间的分界线。2.3 大图切片让人体目标的尺寸回到“看得清”的水平原始航拍单帧图像尺寸为3840x2160如果直接缩放到YOLO常用的640分辨率输入操场上的一个人就只剩不到10个像素宽了这已经不是训练技巧可以解决的问题。因此必须对大图进行滑窗切片把大图拆成若干有重叠的局部区域再作为训练样本。我的切片配置是1024x1024的窗口横向和纵向步长均为768也就是25%的老重叠。这种重叠设计是为了避免人群中恰好跨越窗口边界的目标被切断导致标注信息不完整。切片后一个目标的像素尺寸会提升到原来的3到4倍模型终于有足够的特征来判断“这是一个俯拍的人”了。需要注意的是切片会丢弃部分跨边界目标这些目标可以在标注阶段直接忽略不进入训练集。如果你直接用滑窗切片后的整图去做检测并期望还原到原图坐标训练前最好记录每张切片在原图中的起始坐标推理阶段再做坐标换算。3. 标注规范与格式转换小目标人体标注的完整约定标注是制作数据集时最耗时、也最容易返工的环节。我见过不少同行标到一半发现标准不统一不得不推倒重来。特别是航拍俯拍场景人体的可见形态和平视差异很大提前定好标注规范能让你少走很多弯路。3.1 小目标与遮挡目标的判定标准在俯拍画面中人体有可能是完整可见的也可能是被树木、栏杆、其他人员部分遮挡的。我的标注规范参考了常见目标检测竞赛的处理方式把目标分为两类清晰可见的完整人体标记为“person”严重遮挡或头部被遮挡的标记为“ignore”。需要说明的是ignore类目标并不参与训练损失计算但会在标签文件中单独保留方便后续做难度分析。对于你决定要标注的目标我建议遵循一个简单原则只要目标在切片中像素高度大于15像素且其主要轮廓头部加肩部清晰可见就标注出来。低于这个尺寸的目标人眼都很难确认强行标注只会给模型带入噪声。我在实际操作中发现小于15像素的目标即使标了模型也很难学到有效特征反而会拉低整体精度。这个阈值可以根据你最终推理的分辨率灵活调整但一定要保持全数据集统一。遮挡情况需要一个明确的截断标准。例如一个学生站在操场边的大树底下半个身体被树冠遮住只露出腿脚究竟算不算一个正样本我的处理是如果头部和上半身被遮挡则标记为ignore如果只是腿部被遮挡头部和躯干可见仍然标记为person。因为俯拍视角下模型实际上主要也是通过头肩区域来识别目标腿部被遮影响相对较小。3.2 标注工具与效率技巧标注工具我推荐用X-AnyLabeling或者基于Web的CVAT。X-AnyLabeling的优势是支持导入YOLO格式并且可以加载已有的模型进行预标注标注员只需要检查修正即可。我的流程是先用一个初始版本模型对所有切片做自动预测导出一份粗糙标签然后人工逐张修正。这样可以大幅减少从零画框的时间尤其是画面中人员密集的时候预标注配合手动调整效率能提升一半以上。在标注过程中尺寸太小的目标用矩形框即可不需要做分割掩码。矩形框要贴合目标边界尽量少包含背景尤其要避免把相邻同学的阴影框进来。我用的是矩形框贴边原则上边紧贴头顶左右贴着肩部外沿下边到臀部或者脚部取决于俯拍角度下能看到多少身体。记住一点标注的真实性和一致性比标注本身的“精致”更重要。一批标注稍微偏大、但边界判断标准统一的样本训练效果通常优于一批时大时小、标准混乱的样本。3.3 从任意格式到YOLO格式的转换脚本我最初标注时导出的是VOC格式的XML文件而YOLO训练需要的是txt格式且坐标归一化到0到1之间。下面这段Python脚本可以直接把XML转换成YOLO格式的txt核心逻辑是把边界框的绝对坐标转换成中心点坐标加上宽高并除以图像宽高归一化。import os import xml.etree.ElementTree as ET def convert_voc_to_yolo(xml_path, output_dir, classes): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) txt_name os.path.splitext(os.path.basename(xml_path))[0] .txt txt_path os.path.join(output_dir, txt_name) with open(txt_path, w, encodingutf-8) as f: for obj in root.iter(object): name obj.find(name).text if name not in classes: continue class_id classes.index(name) xmin float(obj.find(bndbox/xmin).text) ymin float(obj.find(bndbox/ymin).text) xmax float(obj.find(bndbox/xmax).text) ymax float(obj.find(bndbox/ymax).text) x_center ((xmin xmax) / 2) / img_w y_center ((ymin ymax) / 2) / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h f.write(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n) if __name__ __main__: classes [person] xml_dir label_xml out_dir labels_yolo os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): convert_voc_to_yolo(os.path.join(xml_dir, xml_file), out_dir, classes)切片后的图像和生成的标签文件必须使用相同的文件名前缀这样才能被YOLO训练脚本正确关联。我一开始就是因为重命名切片时前缀弄错了结果训练时发现很多图像找不到标签白白浪费了一个下午排查。建议你在切片阶段就把文件名规则定义好例如“campus_00001_1024_768.jpg”这种将原始大图编号与切片的起始坐标编码进文件名便于追溯问题切片。4. YOLO训练配置模型选型、数据集划分与关键参数训练配置直接决定模型的上限。网上关于YOLOv8、YOLOv9、YOLOv10的对比已经很多但在航拍小目标这个具体任务上我的感受是与其纠结“最新最强”版本不如先把训练配置和数据配比一次做对。4.1 模型选型为什么我在航拍人体检测上用YOLOv8航拍操场的检测目标是典型的小目标密集场景而不是追求极致速度的实时视频流场景因此模型需要在小目标召回率上更稳。YOLOv9和YOLOv10在部分基准上有更亮眼的表现但YOLOv8的成熟度和生态稳定性占优尤其是对自定义数据集的训练、导出和部署流程资料与经验都非常丰富。如果你手头资源有限我建议从YOLOv8m或者YOLOv8l开始体验会比YOLOv8n好很多。YOLOv8n胜在速度快、模型小但航拍俯拍小目标对模型容量要求高轻量模型的特征表达能力在小目标上明显吃力。我用YOLOv8n做过一轮测试mAP0.5比YOLOv8m低了好几个点存在大量的漏检尤其是小目标。YOLOv8l在精度上更好但对显存有一定要求。如果你是入门复现YOLOv8m是最均衡的起点。等验证流程跑通后再根据实际部署设备决定是否需要蒸馏成轻量模型。4.2 数据集划分与配置文件整个数据集我最终保留了大约5200张切片图像其中训练集占70%验证集20%测试集10%。这里必须注意全部切片来自几十张大图如果划分时简单随机同一张大图中相邻切片的内容高度相似很容易让验证集“泄漏”也就是模型在训练时已经见过验证集的近似内容导致评估分数虚高。正确做法是以大图为单位进行划分确保同一张大图的切片不会被同时分到训练集和验证集。我建议你在划分前先按大图编号整理再按大图粒度切分而不是直接shuffle所有切片。下面是我用的一个简单YAML配置train: /data/campus_playground/train/images val: /data/campus_playground/val/images test: /data/campus_playground/test/images nc: 1 names: [person]训练时imgsz我设为1024而不是默认的640。因为我的切片本身是1024x1024输入分辨率太小时目标尺寸会被进一步压缩。代价是训练显存占用增加不少但小目标检测本来就是“用分辨率换召回率”这个调整非常划算。4.3 训练参数与反向传播稳定性训练参数中比较关键的是epochs、batch size和优化器配置。我跑的是250个epochbatch size根据显卡显存调整到了16。如果你用更大的分辨率batch size可以相应降低但不要低于8因为batch太小极易引发训练不稳定也就是很多人遇到的“BN崩溃”问题。现象是loss突然变成nan或者训练过程中mAP断崖式下跌。这通常是因为batch size过小导致BatchNorm层的统计量抖动太大。如果你显卡显存有限优先考虑减小imgsz而不是无限减小batch毕竟对航拍小目标来说分辨率比batch size更宝贵。学习率上我使用的是SGD初始学习率0.01配合余弦退火。很多初学者在YOLOv8上直接用Adam但实测下来SGD在目标检测任务上依然非常稳。训练过程中我还会开启YOLOv8自带的Mosaic数据增强它能把四张图像拼接成一张等于变相增加了小目标的分布密度对提升泛化非常有帮助。但在训练后期可以适当关闭Mosaic让模型在比较正常的输入分布上做微调避免最终推理时对拼接图产生依赖。关于loss曲线我想多说一句不要只看总loss下降就以为训练成功了。我实际观察早期训练时分类损失和框回归损失下降得很快但小目标特有的低置信度漏检很难直接从总loss上看出来。因此训练完一定要用验证集做详细的小目标AP分析而不是只看一个大而化之的mAP数值。5. 实测评估与调优从mAP到真实飞行场景的差距模型训练结束后我先在测试集上做了一遍评估mAP0.5达到了预期的水平当时心里还挺满意。可把模型部署到一台小型边缘计算设备上再带着无人机飞到操场实时推理时发现情况完全不是那么一回事。测试集上的表现和真实场景之间的差距主要来自三个方面天气光照变化、飞行高度偏移以及推理分辨率限制。5.1 评估指标怎么看小目标AP比总mAP更重要YOLOv8训练结束后会输出很多指标我最关注的是不同尺寸目标的AP。查看验证集结果时你会发现模型在中等尺寸目标上的AP可能已经在80以上了但小目标AP可能只有40到50这是航拍场景最常见的现象。判断一个模型能不能用不能只看mAP0.5因为mAP0.5对框位置要求相对宽松只要目标大致被框住就算正确更严格的是mAP0.5:0.95它更看重边框质量对航拍场景来说也更有参考意义。我在做小目标分析时会把验证集里的目标按像素面积分成三档面积小于32x32像素的为小目标32x32到96x96之间的为中目标超过96x96的为大目标。然后分别统计每一档的召回率。实测下来模型漏检的大部分是小档目标。如果你的模型也存在这个问题请先回到数据和标注层面排查是标注时漏标了还是切片分辨率不够抑或是模型容量不足。盲目堆测试时调阈值不是解决根因的办法。5.2 真实飞行测试中的误检与漏检带着模型回到操场实测最常见的问题是阴影误检。晴天下午学生跑到草坪上做操时每个人的身体旁边都拖着一道影子。俯拍视角下影子和人的轮廓区域接近且颜色相对统一模型很容易把影子当成一个人来框。我在后处理中尝试调整置信度阈值从默认的0.25提高到0.35误检确实少了但也牺牲了部分小目标召回率。另一个问题是密集排队场景下的漏检。在做课间操队形时学生排列整齐前后左右间距很小模型容易把相邻的几个人合并成一个框或者只检出一个而漏掉旁边的人。这类问题靠调阈值解决不了我建议在训练数据中专门保留一些密集队列场景的切片并适当增加这类样本的采样权重。同时在推理阶段把NMS的IoU阈值从默认0.7适当调低到0.5减少相邻目标被“压制”掉的情况。5.3 数据增强与后处理优化的小技巧在后续迭代中我明显感受到几个增强操作对航拍小目标的回报率高。第一个是随机缩放增强范围设在0.5到1.5之间让模型适应不同飞行高度带来的尺度变化。第二个是随机亮度对比度调整模拟不同天气和光照条件。第三个是水平翻转和旋转操场场景中的学生方向变化较大适度旋转增强能提高旋转不变性。但旋转角度不要太大90度倍数以外的旋转会引入不合常规视角的样本。如果推理目标是部署在边缘设备上还有一个简单有效的技巧把输入分辨率固定到和训练时一致不要为了追求速度盲目压缩。举个例子你在训练时用1024分辨率推理时为了跑30帧压缩到640模型在小目标上的精度会立刻下滑。更好的方案是用TensorRT或OpenVINO优化模型而不是牺牲输入分辨率。6. 数据集的价值延伸从人体检测到更多场景化应用做完第一版航拍校园操场人体检测数据集之后我开始意识到它的价值绝对不止一个模型权重那么简单。这个数据集解决的是“俯拍视角下的小目标人体检测”这个通用问题它的应用范围可以横向扩展到很多同类场景。6.1 校园场景里的进一步应用人群密度与轨迹分析有了稳定的人体检测结果下一步自然就是人群密度估计和人员轨迹分析。通过把相邻视频帧的检测框关联起来可以统计某个区域内人员的停留时间、流动方向以及瞬时人数。对体育课来说可以辅助统计学生是否在规定区域内活动对大型集会而言可以用于人群异常聚集的预警。这些都不是我凭空想出来的方向而是我在项目中已经验证过可行或正在尝试的扩展。轨迹分析需要比较稳定的检测框因为跟踪算法依赖目标的位置连续性。如果你的检测框出现抖动跟踪轨迹会频繁断裂。一个很实用的做法是引入简单的卡尔曼滤波或ByteTrack这类轻量级跟踪算法对检测结果做时序平滑。我在实测中发现使用ByteTrack配合YOLOv8检测结果课间操场景下的人群轨迹基本能够保持清晰连续足够支撑后续的统计需求。6.2 跨场景泛化与样本迭代做数据集的人都知道数据集永远没有“做完”的那一天。目前这个数据集主要覆盖的是晴天、白天、单一校园操场的场景。后续如果想让它更有普适性我建议采集不同季节、不同天气阴天、多云、雨后、不同时间段清晨、傍晚的数据并标注进来。还可以加入部分运动场、足球场这类与操场类似的场景提升模型在不同地面环境中的泛化能力。我在迭代过程中还发现把检测错误的样本单独整理出来加入训练集是一种非常高效的“难例挖掘”方式。具体操作是用当前模型跑一批新的无标注航拍素材把置信度很低但人眼能辨认出人体的目标筛选出来人工修正后并入训练集。这种方式比随机补充数据更能针对性改善模型短板。不过难例挖掘要注意控制比例一个数据集里全是难例会让模型训练不收敛一般建议新增难例不超过原训练集的10%到20%。6.3 数据集的发布与合规脱敏如果你计划像标题提到的那样把这个数据集发布出来供同行使用合规问题一定要放在前面。航拍校园数据涉及未成年人肖像和地理位置信息直接发布原始图像风险很大。我的做法是离线用检测算法对所有人脸区域做高斯模糊同时对图像中的学校名称、标志性建筑等可识别信息做遮盖处理。进一步地你还可以只发布YOLO格式的标签文件和对应的脱敏后图像不公开原始录像。在这个前提下数据集才具备对外开源的可行性。第二个值得注意的细节是标注文件版权。标注框坐标本身虽然属于客观事实但整理、清洗、校验这些工作凝聚了不少人力成本。发布时建议明确数据集的使用许可例如仅限学术研究、禁止商用转售等。这样既能保护自己的劳动成果也能让使用者在明确规则下放心使用。整条链路走到这里我觉得最有价值的并不是那一个精度还挺好看的权重文件而是你真正理解了航拍视角下小目标检测的数据难点和工程坑位。做数据集和训练模型的过程本质上是不断和数据、和模型细节斗争的过程。如果你也准备从零开始做一套航拍人体检测数据集希望我记录下的这些参数配置、标注约定和踩坑经验能让你少走一段我走过的弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑