基于深度学习的工地危险区域入侵检测监控告警系统实现

📅 发布时间:2026/9/16 1:45:33
基于深度学习的工地危险区域入侵检测监控告警系统实现
简介这是一份面向智慧工地场景的深度学习入侵检测告警系统源码基于主流目标检测框架主要解决施工区域危险地带人员误入的实时监控问题。资源适合计算机相关专业学生、教师或企业开发者可用于毕业设计、课程设计、大作业及项目预研具备良好的二次开发空间。压缩包共九十二个文件包含十八个脚本、二十三个编译文件、十七个配置文件、三个预训练模型以及三段检测演示视频另有少量图片、标注文件及部署配置整体大小八十四点三兆。目前已有134人学习下载。项目功能完整可识别搅拌车、吊车等机械和作业工人支持自定义绘制危险区域一旦检测到工人闯入即触发告警信息并发出语音提醒同时支持本地图片、视频及网络视频流检测部署门槛低运行稳定方便在此基础上进行算法优化和功能扩展。1. 从“人盯屏幕”到“AI盯现场”这个标题在解决什么塔吊下方的钢筋堆场、基坑临边、高压电箱周围这些区域在工地监控画面里毫无视觉特征但每一步误入都可能出大事。传统的做法是安排安全员轮班盯监控但一个中等规模的工地动辄几十路摄像头人的注意力很难持续超过二十分钟等发现有人越线时往往事故已经发生。基于深度学习的工地危险区域入侵检测监控告警系统就是干这件事的用目标检测模型实时识别画面中的人员再通过坐标逻辑判断人员是否进入预定义的电子围栏区域一旦越界立刻触发告警。这个系统用 Python 组织整个链路模型推理由深度学习框架完成告警部分可以挂声光报警器也可以只做界面闪烁和截图留存。无论你拿到的压缩包里是训练好的权重文件还是未训练的模型结构这篇博文会把这套系统的完整实现路径讲清楚模型怎么选、危险区域怎么定义、人员检测框和区域多边形怎么算交集、误报怎么压、阈值怎么调。适合要做毕业设计的学生也适合工地安全信息化项目的开发者在进场前把技术checklist过一遍。下面直接进入实现。2. 深度学习模型选型为什么 YOLO 是工地入侵检测的最优解2.1 入侵检测的本质是“先检出人再判断位置”工地危险区域入侵检测的第一层任务不是分类行为而是锁定画面中每个人的位置。安全帽佩戴检测需要判断头肩区域入侵检测则直接关心人的脚底坐标——因为最后一步与电子围栏做空间关系判断时需要把二维检测框底部中心点当作人的地面落脚点。对这类场景目标检测算法家族里能用的方案无非两大类两阶段检测器和单阶段检测器。两阶段方法如 Faster R-CNN先产生候选区域再逐区域分类回归精度高但推理速度很难在普通工控机上跑到实时。单阶段方法直接从图像回归出边界框和类别YOLO 系列是这一路线的代表在 RTX 3060 级别显卡上跑 640×640 输入能达到 60 FPS 以上配合 DeepSORT 之类的跟踪器还能给每个目标分配持续稳定的 ID。需要说明的是model.pt里的权重文件决定模型能不能认出“人”这个类别。如果网络是 COCO 预训练权重person 类拿过来就能做通用行人检测但如果工地上有大量俯视视角的摄像枪装在灯杆上向下看建议用工地场景数据做微调。俯视视角下人的外形特征和 COCO 数据集中偏水平视角的行人差异不小漏检率会明显上升。2.2 用一张命令验证模型能不能立即工作下载或拿到项目源码包之后先不要急着改告警逻辑。第一步是把模型跑通确认权重文件和输入输出尺寸正常。下面是验证模型的基本代码适用于任何基于 Ultralytics YOLO 的工程from ultralytics import YOLO # 加载模型权重v8n 是最小的 nano 版本实测精度低但速度快 model YOLO(yolov8n.pt) # 跑一张测试图保存预测结果 results model.predict(sourcetest.jpg, conf0.25, saveTrue) # 输出类别索引和置信度 for r in results: for box in r.boxes: print(box.cls, box.conf, box.xyxy)conf0.25的意思是低于 0.25 置信度的检测框会被丢弃。工地场景中远距离的小目标距离摄像头 20 米外的人置信度往往只有 0.3~0.5如果卡到 0.6 以上会出现大面积漏检。我一般在这个环节不做太多调优先确认模型能被正确加载并输出检测框再做危险区域判定。2.3 尺寸正方形化的坑YOLO 系列在预处理阶段要求输入尺寸能被 32 整除因为 CSPDarknet 的前向传播包含 5 次下采样默认通常是 640×640。但工地的监控画面是 16:9 的宽幅视频直接用默认尺寸送入模型图像会被拉伸人体比例失真小目标检出率下降。实际项目中常见的做法是保持宽高比做 letterbox 处理即在图像四周填充灰色条带使短边等于 640。Ultralytics 框架在推理时默认已经做了这层处理不需要重复写。但如果你从源码包里看到的是纯 PyTorch 实现的推理脚本那么自己补一下 letterbox 的逻辑是必须的否则检测框坐标会整体偏移后面算电子围栏交集就全错了。3. Python 实现危险区域判定与告警逻辑3.1 预先定义电子围栏用多边形代替矩形危险区域很少是规则的矩形。塔吊臂下方的覆盖范围是一个扇形基坑边缘是折线配电箱周围可能只是一个 2 米见方的小方块。如果只用 OpenCV 的矩形框(x, y, w, h)去表达会带来大量误报——人在矩形对角线覆盖的无效空间里也会触发告警。因此实现时应定义一个多边形类用顶点列表描述危险区域。下面是用 NumPy 实现点与多边形位置关系的代码采用了射线法Ray Casting判断点是否在区域内import numpy as np def point_in_polygon(point, polygon): 射线法判断点是否在多边形内部 :param point: (x, y) 人的脚底位置 :param polygon: 多边形顶点列表 [(x1, y1), (x2, y2), ...] :return: True 表示在区域内 x, y point n len(polygon) inside False p1x, p1y polygon[0] for i in range(1, n 1): p2x, p2y polygon[i % n] if y min(p1y, p2y): if y max(p1y, p2y): if x max(p1x, p2x): x_intersect (y - p1y) * (p2x - p1x) / (p2y - p1y) p1x if p1x p2x or x x_intersect: inside not inside p1x, p1y p2x, p2y return inside射线法的思路是从目标点向左发一条水平射线统计与多边形边的交点个数奇数则在内部偶数则在外部。这段代码中x_intersect计算的是射线与边的交点的 x 坐标当目标点 x 小于等于交点 x 时翻转状态。判断逻辑并不复杂真正要留意的是“人的哪个点作为落脚点”。检测框(x1, y1, x2, y2)是矩形包围盒矩形底部中点((x1 x2) // 2, y2)对应人的地面位置用这个点去和区域碰撞比用矩形中心和矩形左上角更符合人的空间直觉。3.2 告警触发加状态机防止重复报警刷屏如果每一帧检测到人进入区域就触发一次告警25 FPS 的视频流会让告警系统每秒弹出 25 条消息。这在实际项目里完全不可用。正确的做法是引入告警状态机每个目标有PRE_ALARM预告警、ALARM确认告警、CLEAR清除三种状态当同一目标连续 N 帧处于危险区域内时才确认告警离开区域后延迟 M 秒再解除。下面给出一个简单的目标级状态管理实现class AlertStateMachine: def __init__(self, trigger_frames5, clear_seconds3.0): self.trigger_frames trigger_frames # 连续多少帧触发 self.clear_seconds clear_seconds # 离开后多少秒解除 self.frame_count 0 self.alert_active False self.last_seen_time None def update(self, in_zone, current_time): if in_zone: self.frame_count 1 self.last_seen_time current_time if self.frame_count self.trigger_frames: self.alert_active True else: # 减少计数避免瞬时抖动造成误触发 self.frame_count max(0, self.frame_count - 1) if self.alert_active: if current_time - self.last_seen_time self.clear_seconds: self.alert_active False return self.alert_activetrigger_frames5表示同一个人连续 5 帧出现在危险区域内才触发这个值在 25 FPS 下约等于 0.2 秒。参数太小跑步路过区域边缘就会误报参数太大慢速走进塔吊下方的人要 1 秒多才告警失去了提前预警的意义。工程上一般取 3~8 帧之间你可以按现场安全员对响应速度的要求调整这个值。3.3 告警动作的三个落点告警不只是弹一个窗。一个工地级的监控告警系统通常需要同时做三件事。第一是现场声光告警通过继电器控制报警灯和蜂鸣器用 Python 的serial库向串口发送开合指令即可第二是监控大屏端弹窗用 OpenCV 在原图上画红框并标注“ALARM: Person in Danger Zone!”同时保存截图和短视频证据第三是管理后端的日志入库把告警时间、摄像头编号、人员检测框坐标写成 JSON 或写入数据库。下面是在视频帧上绘制告警信息的 OpenCV 代码片段这些逻辑在无人值守场景中非常常用import cv2 # 假设 frame 是当前帧zones 是危险区域多边形列表 alert_color (0, 0, 255) # BGR 红色 normal_color (0, 255, 0) # BGR 绿色 # 在画面左上角显示状态文字 status_text ALARM if alert_active else MONITORING color alert_color if alert_active else normal_color cv2.putText(frame, status_text, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1.2, color, 2) # 绘制危险区域多边形轮廓 for zone in zones: pts np.array(zone, np.int32).reshape((-1, 1, 2)) cv2.polylines(frame, [pts], isClosedTrue, coloralert_color, thickness2)OpenCV 的polylines要求点的形状为(n, 1, 2)可以直接把多边形顶点列表传进去。绘制轮廓的目的是让现场操作人员能直观看到电子围栏的范围如果区域画得不对调起来会非常痛苦。4. 模型训练与精度调优把通用检测器变成工地专用4.1 数据集从哪里来工地场景的行人检测数据集有三个来源按质量高低排序一是现场监控录像的抽帧标注周期大概一周能覆盖不同光照、不同机位、不同工装颜色效果最好二是公开的工地数据集如上海交大的 SJTU 建筑工地数据集或 AI Challenger 行人数据集做补充三是合成数据用 SKY 引擎或游戏引擎渲染工地场景但不建议依赖这种方案和真实监控画面的域差异很大。标注格式按照 YOLO 需要的 txt 格式组织每个标注文件对应一张图片每一行是class x_center y_center width height四个坐标值均为相对图像的 [0,1] 比值。假设一张 1920×1080 的图中人的检测框左上角在 (960, 270)右下角在 (1050, 720)那么标注应该是0 0.5234 0.4583 0.0469 0.4167x_center为(960 1050) / 2 / 1920 0.5234width为(1050 - 960) / 1920 0.0469。用 LabelImg 或 labelme 这样的图形化标注工具画框导出时选择 YOLO 格式这些换算工具会自动完成但你最好能手工验算一两次确保标注流程没被配错。4.2 训练参数配置矩阵微调一个 YOLOv8 模型关键参数只有六个epochs、batch、imgsz、optimizer、lr0、patience。下面给出一组用于工地场景微调的基础参数配置# config.yaml 部分内容 path: ./dataset train: images/train val: images/val # 类别定义这里只检测 person 一类 names: 0: personfrom ultralytics import YOLO # 加载预训练的 yolov8n 权重开始训练 model YOLO(yolov8n.pt) results model.train( dataconfig.yaml, epochs100, batch16, imgsz640, optimizerAdamW, lr01e-3, patience10, cacheTrue, )epochs100对工地一个类别的微调来说是偏多的因为预训练模型已经能识别通用的 person 类只需要适应工地视角的分布。patience10的意思是连续 10 轮在验证集上没有提升就提前停止防止过拟合。工地的数据集通常在 2000~5000 张之间100 轮的训练时间在 RTX 3060 上约 2~4 小时。精细调整时关注两个指标一是mAP50也就是 IOU 阈值为 0.5 时的平均精度稳定到 0.9 以上说明模型已经把“人”找全了二是 recall即“实际存在的人中有多少被检出来”这个指标比 precision 更重要因为漏掉一帧意味着可能错过一次告警。4.3 三个提精度的必调方向如果微调之后依旧存在漏检或误检优先从三个方向入手。第一个方向是给模型加注意力模块7×7 的 SE 注意力或坐标注意力CA可以显著提升小目标的特征响应yolov8m 及以上模型结构自带部分注意力机制你优先使用更大的模型架构而非魔改结构。第二个方向是数据增强Ultralytics 默认的增强策略中包含马赛克增强和随机透视变换对工地这种人少、背景杂的数据集把mosaic0.8左右的概率保持住能有效缓解背景过拟合。第三个方向是降低conf_thres在部署推理时从 0.25 降到 0.15代价是每帧多出几个误检框但这些误检框只要不在电子围栏区域内就不会触发告警用告警状态机的空间换召回率。5. 部署实战把检测视频流接进来并实测误报率5.1 用 RTSP 流接入海康摄像头工地上已经有了现成的监控网络没必要强行用 USB 摄像头。海康、大华等品牌的监控摄像头支持 RTSP 协议实时取流最直接的方式是用 OpenCV 的VideoCapture解码 RTSP 流得到 BGR 帧后再送入 YOLO 推理。典型 RTSP 地址格式是rtsp://username:password192.168.1.64:554/Streaming/Channels/101其中101对应主码流102对应子码流。主码流分辨率一般是 1080P码率在 4Mbps 左右适合做检测但工地网络带宽不够时可以用子码流检测、主码流抓图的折衷策略。import cv2 from ultralytics import YOLO # 加载模型和视频源 model YOLO(best.pt) cap cv2.VideoCapture(rtsp://admin:password192.168.1.64:554/Streaming/Channels/101) while cap.isOpened(): ret, frame cap.read() if not ret: break # 推理并拿到检测结果 results model(frame, conf0.25, imgsz640)[0] # 拿到人这个类别class_id0的检测框 boxes results.boxes.xyxy.cpu().numpy() classes results.boxes.cls.cpu().numpy() persons [box for box, cls in zip(boxes, classes) if cls 0] # 后续取 box 底部中点和危险区域做碰撞判断 for box in persons: x1, y1, x2, y2 box.astype(int) foot_point ((x1 x2) // 2, y2) # 判断 foot_point 是否在多边形内触发告警状态机 # 显示画面 cv2.imshow(Danger Zone Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()results.boxes.xyxy返回的是绝对值坐标不是归一化坐标坐标参考系与原始图像一致。这里没有对person类做过滤的话模型如果同时训练了安全帽类别会把安全帽的检测结果也给进来因此你需要确认classes等于 0 的过滤条件。5.2 实测阶段的误报率评估方法系统搭完不能直接交付需要做一轮量化评估。找一个包含正常运行和人员入侵的 1 小时录像把系统跑一遍手动统计两个数据入侵事件真实发生的次数和系统告警总次数。求得两个指标漏报率该报的时候没报和误报率不该报的时候报了。工地场景的验收标准一般参考安全生产规范漏报率必须为零误报率在 10% 以内。降低误报的关键是识别“非人目标”为什么会闯入围栏。工地现场最大的假阳性来源有两个一是地面上的影子在强光下被检测成人形二是运材料的工人推着斗车斗车的形状和人的轮廓拼接在一起被拆成两个目标。针对影子问题可以限制检测时间段夜间模式下提高置信度阈值到 0.4针对斗车问题需要增加训练数据中带斗车遮挡的样本让模型学会把斗车后面的人检出来。5.3 用 Gradio 快速验收演示如果你拿到的是一个带检测视频的源码包其中通常会有 demo 视频用于快速验证。除了跑完整代码你也可以用 Gradio 写一个单文件演示界面上传视频就能看到检测结果、告警状态和危险区域叠加图。这个步骤对答辩或项目演示很有用20 分钟就能完成import gradio as gr import cv2 import numpy as np from ultralytics import YOLO model YOLO(best.pt) def process_video(video_path): cap cv2.VideoCapture(video_path) frames [] while cap.isOpened(): ret, frame cap.read() if not ret: break results model(frame, conf0.25)[0] annotated results.plot() # Ultralytics 自带画框方法 frames.append(annotated) cap.release() # 用帧序列合成输出视频写入临时目录 out_path output_demo.mp4 h, w, _ frames[0].shape writer cv2.VideoWriter(out_path, cv2.VideoWriter_fourcc(*mp4v), 25, (w, h)) for f in frames: writer.write(f) writer.release() return out_path gr.Interface(fnprocess_video, inputsgr.Video(), outputsgr.Video(), title工地危险区域入侵检测).launch()results.plot()是 Ultralytics 框架封装好的可视化方法它会把检测框、类别名和置信度一次性画在图像的拷贝上。需要注意的是plot()返回的图像是 RGB 排列而 cv2.VideoWriter 默认期望 BGR如果颜色显示异常记得在写入前做cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)转换。6. 进阶技巧告警录制与 FIFO 回写机制部署阶段有一个高频需求告警发生后要回看现场。直接把告警前后 10 秒的视频保存下来既满足安全监管要求也方便后续复盘调整电子围栏坐标。这里推荐一个很实用的实现维护一个环形缓冲区持续存储最近 N 秒的检测帧当状态机翻转为告警时把缓冲区中的帧连同后续告警时段的帧一起合成为 MP4 文件。下面是基于collections.deque的环形缓冲实现该数据结构在 Python 中按最大长度自动丢弃最旧元素from collections import deque import cv2 import time class PreRecordBuffer: def __init__(self, pre_seconds5, fps25): self.maxlen pre_seconds * fps # 5 秒的帧数 self.buffer deque(maxlenself.maxlen) def add_frame(self, frame): self.buffer.append(frame.copy()) def flush_to_video(self, output_path, fps25): writer None for frame in self.buffer: if writer is None: h, w, _ frame.shape writer cv2.VideoWriter( output_path, cv2.VideoWriter_fourcc(*mp4v), fps, (w, h) ) writer.write(frame) self.buffer.clear() if writer: writer.release()deque(maxlenN)在数据量达到 N 后会从左侧弹出旧数据天然适合做滑动窗口。告警触发后调用flush_to_video保存的就是告警前 5 秒的历史画面。这个机制在安防监控系统中叫“预录制”是评判一套告警系统是否真正专业的分水岭——没有预录制的告警视频往往只能拍到人已经在危险区域内的画面而看不到他是怎么走进去的责任认定时少了一半信息量。这套系统到最后你会发现占用时间最多的永远不是模型训练而是2.3节提到的坐标一致性问题、3.2节里的状态机调参以及异常视频源导致的画面冻结。先跑通离线视频再接 RTSP最后再挂声光报警器按这个顺序进场最稳。本文还有配套的精品资源点击获取