ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

监控打架检测数据集:3000张真实场景图与YOLO11训练实战

2026/9/30 2:10:21 拓冰建站 浏览量
监控打架检测数据集:3000张真实场景图与YOLO11训练实战 简介一份面向监控场景智能安防的目标检测数据集配套资源聚焦打架/群殴行为识别适用于需要训练YOLO等检测模型的开发者或项目团队。数据包含真实监控视角的街道、酒吧、商店、公交车、监狱、空旷地等丰富场景两人打架与多人斗殴均有覆盖统一标注为fight单类别并已转为VOC xml、COCO json、YOLO txt三种常用格式可直接用于模型训练。附带的YOLO11一键训练脚本兼顾GPU(GPUs)、CPU、Mac(M芯片)多平台运行另附博主训练结果日志可供效果参考。由于数据集体量较大资源以PDF形式交付内含数据集详细介绍与百度网盘获取方式文件总数1个大小5.63MB。目前已有853人学习下载适合作为监控打架检测项目的数据补充与算法落地练习。1. 打架检测数据集3000 张真实监控图为什么比公开“漂亮图”更好用监控安防里的打架检测最容易翻车的不是漏检而是误报。同事搭个肩膀被框成打架朋友推搡玩闹被框成打架——这种误报在真实项目里比漏检更让人抓狂。我曾在商场项目里被这类问题折磨过一阵最后发现模型本身没问题问题出在数据从网上爬来的打架图太“干净”和真实摄像头俯拍、遮挡、暗光的环境差距太大。这份打架检测数据集核心价值就是它的场景定位3000 张图片全部取材真实监控视角街道、酒吧、商店、公交车、监狱、空旷地全覆盖统一标注为单一 fight 类别用 labelimg 标好同时给出 VOC XML、COCO JSON、YOLO TXT 三种格式拿到就能喂给目标检测框架不用再自己折腾格式转换。配套还有一份 YOLO11 一键训练脚本支持 GPU、CPU、MacM 芯片三平台附带了训练日志参考。适合两类人一类是做监控安防打架检测落地的工程师另一类是已经跑通目标检测流程、想补充真实场景数据的开发者。2. 数据分布与标注细节六大场景、单类别 fight 的构成分析2.1 六大真实监控场景从街道到监狱的数据构成数据集覆盖了打架事件最容易出现的六类监控场景。街道场景的特点是多人聚集、目标距离远、逆光和夜间曝光差酒吧场景则是低照度加霓虹灯偏色暗光条件下的肤色和衣着纹理几乎无从分辨商店场景是固定机位俯拍货架遮挡严重人经常被切成上下两段公交车场景空间狭窄、镜头离人近肢体动作幅度大时会出画监狱场景摄像头安装高度普遍在 4 米以上大俯角让人体轮廓压缩得很厉害空旷地场景背景干净但目标小模型很容易漏检。为什么场景分布要专门拿出来说因为监控场景的视觉特征和网上爬来的新闻图片差异很大。摄像头架在 3 到 6 米高度视角是俯视的人多时有严重的相互遮挡。如果训练集全是平视视角的清晰大图模型学到的特征就跟真实环境对不上——这也是很多通用目标检测模型在监控视频上精度明显下降的根本原因。这份数据集全部是真实监控场景解决的就是数据分布偏移问题。从工程角度拿到数据后我建议先做一步分布统计确认标注框的数量和分布是否满足项目预期。这一步看起来冗余却能提前暴露数据划分或导出环节的问题# scan_fight_labels.py import os from collections import Counter def scan_label_distribution(label_dir): 遍历 YOLO 格式标签目录统计每张图片的标注框数量 找出空标签和分布异常提前暴露数据问题。 dist Counter() total_boxes 0 empty_files [] for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue path os.path.join(label_dir, fname) with open(path, r) as f: lines [line.strip() for line in f if line.strip()] dist[len(lines)] 1 total_boxes len(lines) if len(lines) 0: empty_files.append(fname) print(f标注图片数: {sum(dist.values())}) print(f标注框总数: {total_boxes}) print(f单图框数分布: {sorted(dist.items())}) if empty_files: print(f空标签文件: {len(empty_files)} 个) print(前5个:, empty_files[:5]) if __name__ __main__: scan_label_distribution(./labels/train)这段逻辑很简单读每个 txt 文件的行数行数就是这张图里的目标框数量。输出单图框数分布后你可以直观看到数据里是“每张图 1 到 2 个框”居多还是“每张图 5 个以上框”居多。后者说明多人斗殴场景占比高训练时要重点考虑密集遮挡的情况。空标签文件的存在则意味着训练时这张图没有对应的正样本数量多的话会影响训练稳定。2.2 标注规范labelimg 的使用与框定约定数据集使用 labelimg 标注软件完成标注输出的是 VOC 格式 XML 文件后续再统一转换为 COCO 和 YOLO 格式。labelimg 的标注框用 xmin、ymin、xmax、ymax 四个整数像素坐标表示这个约定来自 PASCAL VOC。这里有一个很多人忽略的点labelimg 的默认坐标精度是整数像素对 1920×1080 的监控画面来说一个目标占到 100×200 像素整数的精度损失可以忽略但如果目标很小只有 20×30 像素整数坐标的误差就占到了 5%会影响小目标检测的精度。在标注规范层面最容易被忽略的是遮挡目标和边缘目标的处理。打架发生时人员肢体交叉严重一个框里经常同时出现两个人的部分肢体。通用约定是框住主体的可见部分遮挡过重、完全无法辨认的部位不强标。这个约定直接决定了数据质量的上限。如果用 labelimg 打开这批 XML 文件会发现框大多紧紧贴着人体的可见轮廓而不会刻意扩到整幅画面。验证 XML 完整性是拿到数据集后我推荐最先做的一步# check_voc_xml.py import xml.etree.ElementTree as ET import os def check_voc_xml(xml_dir): 检查 VOC XML 的类别字段和边界框坐标是否合法。 issues [] for fname in os.listdir(xml_dir): if not fname.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, fname)) root tree.getroot() size root.find(size) if size is None: issues.append(f{fname}: 缺少 size 节点) continue w int(size.find(width).text) h int(size.find(height).text) for obj in root.iter(object): name obj.find(name).text bndbox obj.find(bndbox) xmin int(bndbox.find(xmin).text) ymin int(bndbox.find(ymin).text) xmax int(bndbox.find(xmax).text) ymax int(bndbox.find(ymax).text) if name ! fight: issues.append(f{fname}: 未知类别 {name}) if xmax xmin or ymax ymin: issues.append(f{fname}: 非法框 ({xmin},{ymin},{xmax},{ymax})) if xmin 0 or ymin 0 or xmax w or ymax h: issues.append(f{fname}: 坐标越界) if not issues: print(全部 XML 文件检查通过) else: print(f发现 {len(issues)} 个问题:) for item in issues[:20]: print(item) if __name__ __main__: check_voc_xml(./annotations)这个脚本从三个维度卡质量类别名是否严格等于 fight、坐标是否合法右下角必须大于左上角、坐标是否超出图片尺寸。3000 张图的规模手工逐张检查不现实脚本几秒钟就能扫完。如果有问题优先排查标注导出环节而不是直接进训练流程。2.3 单类别的训练陷阱两人打架与多人斗殴的尺度差异数据集只定义了一个 fight 类别但训练时实际要面对的尺度跨度很大。两人打架时目标在画面里的占比通常较大肢体动作清晰框的宽高比接近 0.6 到 1.5多人斗殴时目标密集、互相遮挡很多人只露出半身甚至一个头框的宽高比会拉到 0.3 以下或 2.0 以上。类别名只有一个标注框的几何形态却覆盖了很大的区间。这里有一个训练策略上的分歧要不要把多人斗殴单独拆成一个类别我的答案是不建议。打架检测项目落地时客户的核心诉求是检测出“打起来了”这个混乱状态而不是区分“几个人在打”。硬拆多类别反而会割裂样本的连续性原本可以共享的肢体冲突特征被分到两个类别里每类样本量变小训练难度反而增加。单类别设定带来的直接好处是省去了类别不平衡的处理。但代价是需要把尺度差异通过数据增强来吸收。两人打架场景可以依靠常规的 mosaic、随机翻转多人斗殴场景就要考虑 copy-paste 增强把裁剪下来的人物目标贴到别的背景图上模拟人群密集时部分目标被遮挡的形态。这一点会在第 4 章的训练参数里展开讲。3. 三种标签格式实战VOC/COCO/YOLO 的转换与校验3.1 VOC 的 XML 结构object 节点与四个坐标值VOC 格式是 PASCAL VOC 项目确立的标注标准用 XML 文件承载标注框信息。每个 object 节点对应一个目标框name 节点存类别名bndbox 节点存 xmin、ymin、xmax、ymax 四个像素坐标。坐标基于原始图片分辨率在 labelimg 里看到的就是原图上的绝对位置。这个格式的优点是结构直观、用文本编辑器就能打开检查缺点是文件零散3000 张图就是 3000 个 XML 文件训练时直接读会很拖慢数据加载。所以现代训练流程里VOC 更多作为中间格式存在labelimg 标完输出 XML再统一转成目标框架需要的格式。我拿到 VOC 数据后会用上一章的 XML 校验脚本跑一遍重点确认 size 节点和图片实际分辨率一致、框坐标没有出现 xmax 小于 xmin 之类的非法值。这两类问题都来自标注过程中的手误一旦带着这些脏数据进了训练排查成本会翻好几倍。3.2 COCO 的 JSON 组织categories、annotations 与 image_idCOCO 格式把整份标注集中到一个 JSON 文件里三个核心字段是 images、annotations、categories。images 数组存每张图的 id、file_name、width、heightannotations 数组存每个框的 id、image_id、bbox、category_idcategories 数组存类别编号和类别名。相比 VOC 的文件式管理COCO 更适合大规模数据集的随机访问。从 VOC 转 COCO 时最容易踩的坑是 image_id 的连续性。VOC 里每张图是独立的 XML 文件没有全局编号转换脚本如果漏了某个文件的编号递增COCO JSON 里就会出现 annotations 指向不存在的 image_id训练时数据加载直接报 index out of range。我一般用下面这段代码做 COCO 格式自检# validate_coco.py import json def validate_coco(json_path): 校验 COCO JSON 中 annotations 与 images 的关联完整性 并检查 bbox 宽高是否合法。 with open(json_path, r) as f: data json.load(f) image_ids set(img[id] for img in data[images]) ann_image_ids set() for ann in data[annotations]: if ann[image_id] not in image_ids: print(f标注 {ann[id]} 的 image_id 不存在: {ann[image_id]}) ann_image_ids.add(ann[image_id]) x, y, w, h ann[bbox] if w 0 or h 0: print(f标注 {ann[id]} 的 bbox 非法: {ann[bbox]}) missing image_ids - ann_image_ids if missing: print(f有 {len(missing)} 张图片没有标注: {list(missing)[:10]}) else: print(fCOCO JSON 校验通过共 {len(image_ids)} 图{len(data[annotations])} 框) if __name__ __main__: validate_coco(./annotations/train.json)这段代码做两件事一是检查所有 annotations 的 image_id 是否在 images 里真实存在二是检查 bbox 的宽高是否非负。前者管关联后者管坐标合法性。COCO 的 bbox 是 x、y、width、height 表示注意它和 VOC 的 xmin、ymin、xmax、ymax 不是一回事转换时别直接把四个角点填进去。这里的 x、y 是框左上角坐标width 和 height 是框的宽高都是从 VOC 的四个值推导出来的。3.3 YOLO 的 TXT 标签归一化坐标的转换计算YOLO 格式是最简单的文本格式每张图片对应一个同名 txt 文件每行代表一个目标框格式为 class_id、x_center、y_center、width、height。五个字段中后四个都是归一化浮点数范围在 0 到 1 之间计算方式是把像素坐标除以图片宽高x_center (xmin xmax) / 2 / image_width y_center (ymin ymax) / 2 / image_height width (xmax - xmin) / image_width height (ymax - ymin) / image_height从 VOC XML 转 YOLO txt本质就是解析 XML 再套上面四个公式。转换完成后一定要用 2.1 节的扫描脚本检查归一化坐标是否都在 [0,1] 区间这是最常见的翻车点。转换脚本建议保留在项目 scripts 目录里因为数据集迭代时每合并一批新标注都要重新跑一遍不要每次重写。3.4 三格式选型对比按训练框架决定标签格式格式存储方式单文件含多图坐标单位主流框架适配VOCXML否像素整数Faster R-CNN 系COCOJSON是像素浮点Detectron2、MMDetectionYOLOTXT否归一化浮点Ultralytics、Darknet我的习惯是原始标注永远保留一份 VOC XML 作为底档因为 labelimg 直接输出、结构直观、便于人工排查。拿去做 YOLO 训练的就用 YOLO txt训练时读取最快需要进 MMDetection 或 Detectron2 的项目则转 COCO JSON。格式转换脚本要写注释、保存好因为每次数据集更新都要重新跑一遍。这份数据集三种格式都齐了省掉的是实际项目里最浪费时间的一步格式适配。很多数据集只给 YOLO txt遇到框架要求 COCO 时只能自己写转换脚本转换过程中再踩几个坐标错位的坑半天就搭进去了。三格式齐活意味着拿到手可以在不同检测框架里切换这也是我推荐这份资源的第一个理由。4. YOLO11 一键训练GPU/CPU/Mac 三平台启动与参数解析4.1 环境准备ultralytics 安装与设备检测YOLO11 是 Ultralytics 推出的 YOLO 系列新版本和 YOLOv5、YOLOv8 一样通过 ultralytics 包统一管理。环境安装不算复杂但三平台有细节差异# 创建虚拟环境推荐 Python 3.10 conda create -n yolo11 python3.10 -y conda activate yolo11 # 安装 ultralytics 和 PyTorch pip install ultralytics pip install torch torchvisionGPU 环境装 PyTorch 时要注意 CUDA 版本NVIDIA 驱动 525 以上通常能直接支持 CUDA 12.xMac 用户不需要额外装 CUDAPyTorch 会通过 Metal 接口调用 MPS 后端纯 CPU 环境只要保证 torch 是 CPU 版本即可别不小心装了 CUDA 版导致启动报错。装完后先验证设备# check_device.py import torch from ultralytics import YOLO print(PyTorch 版本:, torch.__version__) if torch.cuda.is_available(): print(GPU 可用:, torch.cuda.get_device_name(0)) elif torch.backends.mps.is_available(): print(MPS 可用Mac M 芯片) else: print(仅 CPU 可用训练速度会明显下降) model YOLO(yolo11n.pt) print(YOLO11 加载成功)运行这段脚本输出会明确告诉你当前环境走的是哪条加速链路。GPU 用户应该看到 CUDA 设备名Mac 用户应该看到 MPS 可用如果两者都没命中那就是纯 CPU 训练需要做好速度和 epoch 上的取舍。加载 yolo11n.pt 时会联网下载预训练权重第一次运行保证网络通畅。4.2 数据 YAML 配置与目录结构数据集按 Ultralytics 的目录约定摆放图片放在 images/train 和 images/val标签放在 labels/train 和 labels/val图片和标签用相同文件名关联。然后写一个 fight_dataset.yaml# fight_dataset.yaml path: ./datasets/fight # 数据集根目录 train: images/train # 训练集图片目录 val: images/val # 验证集图片目录 names: 0: fight这个 YAML 是整个训练流程的入口Ultralytics 读取后会去 path 指定的目录下找 train 和 val 对应的图片文件夹然后自动去同级的 labels 目录里找同名 txt 文件。names 字典的索引必须和标签文件里的 class_id 严格对应fight 对应序号 0。写成 1 的话模型训练时会认为有两个类别但标签里全是 0等于第二个类永远没有正样本训练结果直接废掉。4.3 一键训练脚本三平台的设备选择与 batch 参数数据集配套的一键训练脚本解决的就是跨平台启动问题。脚本先检测可用设备再根据设备类型自动选参数# train_fight.py import torch from ultralytics import YOLO def auto_device(): 按优先级选择 GPU MPS CPU。 if torch.cuda.is_available(): return 0 if torch.backends.mps.is_available(): return mps return cpu def train(): device auto_device() print(f使用设备: {device}) # GPU 显存充足用 16CPU/Mac 降到 8 防止内存压力 batch 16 if device 0 else 8 model YOLO(yolo11n.pt) model.train( datafight_dataset.yaml, epochs100 if device ! cpu else 60, batchbatch, imgsz640, devicedevice, workers4, patience20, augmentTrue, namefight_yolo11, ) if __name__ __main__: train()脚本里几个关键参数在三平台的差异是GPU 环境用 device0 指定第一张卡batch 可以开到 16 甚至 32CPU 环境没有显存约束但算力是瓶颈epoch 建议减半到 60否则时间成本太高Mac 环境用 devicemps 启用 Apple Silicon 的 Metal 加速但 torch 版本要 1.12 以上太老的版本 MPS 后端不可用。patience20 这个参数值得单独说明。它的含义是验证集 mAP 连续 20 个 epoch 没有提升就提前终止训练。3000 张图的中小型数据集YOLO11n 通常在 50 到 80 个 epoch 内收敛到可用状态patience 机制能防止无效的额外训练时间。也可以用 Ultralytics CLI 命令训练效果等同# 单 GPU 训练 yolo detect train datafight_dataset.yaml modelyolo11n.pt epochs100 batch16 imgsz640 device0 # Mac M 芯片训练 yolo detect train datafight_dataset.yaml modelyolo11n.pt epochs100 batch8 imgsz640 devicemps # 纯 CPU 训练 yolo detect train datafight_dataset.yaml modelyolo11n.pt epochs60 batch8 imgsz640 devicecpu提示Ultralytics 训练脚本会把运行结果放在 runs/detect/ 目录下每次运行自动生成新文件夹不会覆盖上一个结果。多个实验对比时看文件夹名即可分辨。4.4 训练日志怎么看loss 曲线与早停判断训练完成后Ultralytics 会在 runs/detect/fight_yolo11 目录下输出 weights/best.pt、weights/last.pt 和 results.png。我一般先看 results.png里面有 box_loss、cls_loss、dfl_loss 三条下降曲线以及 mAP50、mAP50-95 两条验证曲线。正常收敛的图像是三条 loss 曲线从 1.5 到 2.0 逐步下降到 0.5 到 0.8mAP50 从 0 爬到 0.9 左右。如果 loss 在某个 epoch 突然跳高优先怀疑数据增强的随机性或者学习率设置是否过大如果验证集 mAP 在 40 轮后明显回落这是过拟合信号可以把 augment 里的随机透视关掉或者加大训练集的拷贝增强比例。这些判断不一定一次到位但这个数据集配套给了训练日志参考你可以把自己的曲线和参考日志对比看偏差出现在哪个阶段。5. 避坑干货数据校验、设备适配与训练失败的五个高频问题5.1 坐标转换错位训练能收敛但 mAP 始终为零现象训练过程一切正常loss 曲线平稳下降但验证集 mAP 一直为 0打出来的测试图上框完全错位。原因从 VOC XML 转 YOLO txt 时没有做归一化把 xmin、ymin 等绝对像素坐标直接写进了 txtYOLO 训练时会把 1200、800 这样的坐标当作归一化值处理等于目标中心跑到图片外面去了。另一个常见情况是转换时整数除以整数Python 2 时代留下来的整除问题Python 3 里虽然默认浮点除法但如果先做了整数截断再除误差一样存在。解决转换时强制浮点运算所有除法前加 float() 转换再用 3.3 节的校验脚本扫一遍确认坐标都在 [0,1] 区间内。这条是我做过所有格式转换里踩得最多的坑没有之一。5.2 Mac MPS 训练异常M1/M2 芯片训练比 CPU 还慢现象Mac 上训练时 device 显示 mps但训练速度比纯 CPU 还慢甚至中途报 NotImplementedError。原因部分 PyTorch 版本的 MPS 后端实现不完善对特定卷积操作没有提供 kernel 实现运行时回退到 CPU速度比纯 CPU 还差。常见于 torch 1.12 到 1.13 的早期 MPS 支持版本。解决先验证环境运行python -c import torch;print(torch.backends.mps.is_available())确认返回 True。如果训练中报错升级 torch 到 2.0 以上如果只是速度不理想接受用 CPU 跑短周期训练——YOLO11n 在 3000 张图的数据集上CPU 跑 60 个 epoch 也就几个小时并不难接受。5.3 COCO 的 image_id 断裂数据加载报 index out of range现象用 COCO 格式训练时数据加载器报 index out of range大多数出现在 train/val 划分之后。原因划分数据集时直接对 JSON 做数组截断没有同步重排 annotations 里的 image_id导致验证集的 annotation 仍然指向训练集里的图片编号。解决划分脚本里保证 images 和 annotations 两个数组同步重编号。image_id 是 COCO 格式里最容易出问题的字段因为它在两个数组之间建立关联编号一旦断裂整份 JSON 就废了。划分完再跑一遍 3.2 节的校验脚本确认没有 dangling reference。5.4 视频帧运动模糊静态图测试与视频流推理的精度落差现象静态图片测试的精度不错mAP50 在 0.85 以上但换成监控视频流就频繁漏检。原因视频帧有运动模糊打架时动作幅度大四肢的轮廓在单帧里是拖影状态。YOLO 模型对图像噪声有一定容忍度但对边缘模糊比较敏感动作越激烈漏检越明显。解决训练时开启 mosaic 和 copy-paste 增强模拟遮挡和密集场景推理时降低帧率只对关键帧做检测模糊严重的帧直接跳过。如果对实时性要求高可以用上一帧的检测结果做跟踪插值短暂丢失时不置零检测框等目标重新出现再恢复。5.5 类别 id 与 YAML 的 names 映射错乱训练出未知类别现象训练完的模型预测出多个类别或者 predict 时输出的类别名对不上。原因标签 txt 里的 class_id 和 fight_dataset.yaml 里 names 列表的索引没有一一对应。比如数据里写的是 0但 YAML 把 fight 定义成了 1或者前一次标注遗留的 classes.txt 里混进了别的类别。解决训练前统一扫描所有 txt 文件确认 class_id 的覆盖范围只有 {0}。发现非 0 值就做类别重映射把标签修正后再开训练。这一步 10 秒就能跑完但漏掉的话会让训练结果完全不可解释。6. 推理验证与调优习惯从单张图片到监控视频流的完整链路6.1 加载 best.pt 跑通单图和视频推理训练结束后的第一件事不是急着部署而是用 best.pt 跑通一整套推理链路# infer_fight.py from ultralytics import YOLO # 加载训练得到的最佳权重 model YOLO(./runs/detect/fight_yolo11/weights/best.pt) # 单张图片推理 results model.predict( source./test_samples/street_fight.jpg, conf0.4, # 置信度阈值 iou0.5, # NMS 的 IoU 阈值 device0 ) results[0].show() # 监控视频推理支持 RTSP 地址或本地视频文件 results model.predict( source./test_samples/surveillance.mp4, conf0.4, iou0.5, streamTrue )predict 接口的关键参数就两个conf 是置信度阈值低于它的框直接丢弃iou 是 NMS 的 IoU 阈值控制重叠框的抑制力度。device 参数和训练时保持一致GPU 写 0Mac 写 mpsCPU 写 cpu。6.2 置信度阈值与 NMS 的调优监控场景宁可漏检不可误报conf0.4 是我在打架检测项目里的经验值。调低到 0.25 会找回一部分漏检但误报会明显增多——商场里顾客抬手看手机、弯腰系鞋带都可能被当成打架动作调高到 0.6 则误报少但漏检率上升。打架检测的落地场景里误报的代价很高安保人员跑一趟现场却什么都没发生客户的信任度会快速消耗。所以阈值设置的原则是宁可漏检不可误报从 0.4 起步根据客户的误报反馈再逐步上调。iou0.5 在人群拥挤的场景里需要注意。多人肢体重叠时两个框的重叠度可能超过 50%NMS 会把其中一个框抑制掉造成漏检。我一般会把 iou 调到 0.45 给密集场景留出空间同时确认训练阶段已经见过足够多的密集样本。这个值不是固定不变的要和训练数据的密集度配合。从那一次商场项目之后我每次做监控类目标检测项目都会强制走一遍同样的流程先扫标签格式、再转三种格式并逐项校验、然后小步快跑训练、最后按误报反馈调推理阈值。这套习惯并不复杂但能从头到尾堵住数据问题、环境问题和部署问题踩坑的成本就留在了实验阶段。这份打架检测数据集连同场景说明、三格式标签和三平台训练脚本目前以 PDF 文档形式提供下载里面包含数据集的完整介绍和获取方式需要的话可以参考文末的资源获取说明。希望帮到你。本文还有配套的精品资源点击获取