
简介本资源是一套基于YOLO算法的工地安全帽智能识别与预警系统面向人工智能初学者、计算机视觉开发者及建筑行业安全监管技术人员解决施工现场人员未佩戴安全帽的实时检测与告警难题。压缩包共65个文件含15个核心Python脚本如yolo_camera.py、detect.py、mian.py等、28张实测标注图片、7个配置与类别文件voc.names、yolov3-voc.cfg等、1个训练权重文件yolov3-voc_final.weights及1个PyQt界面设计文件detect.ui辅以视频演示、字体资源与日志模块整体大小为457.47MB。目前已有4787人学习下载。资源提供完整可商用源码支持图片单帧识别、本地视频与摄像头实时流检测并内置图形化操作界面配套B站演示视频直观展示99%高识别率效果目录结构按keras-yolo3增强版组织含训练、推理、数据预处理全流程模块便于二次开发与工程部署。 工地安全帽检测这种需求最近几年在建筑施工、能源电力、工厂车间这些领域特别常见。我自己也是被安监部门反复催着才着手做的这个Python版安全帽识别预警系统核心检测用YOLO能跑图片也能跑视频流还做了个简单界面方便现场人员操作。如果你正好也在做类似的事或者想拿YOLO练手做个能落地的视觉项目这篇文章应该能让你少走不少弯路。先说清楚这套东西能做什么输入一张现场照片或者一路摄像头视频流模型自动把画面里的人框出来同时判断这个人有没有戴安全帽。戴了标绿框没戴标红框界面实时显示一旦发现没戴的情况立刻触发预警——界面上弹红字、响蜂鸣器并自动保存一张带标注的截图作为证据方便事后追责和整改。整个项目完全基于Python实现推理部分用YOLO图形界面用PyQt5逻辑清晰改起来也容易。1. 为什么选择YOLO做安全帽检测1.1 工地场景的难点与需求工地的监控场景和生产车间的流水线完全不一样它有几个很棘手的特点。第一是环境乱背景里有塔吊、钢筋、脚手架、移动的车辆甚至还有飘动的旗帜和树影第二是光照不稳定白天强光、傍晚逆光、夜间补光同一个摄像头24小时的光线变化能让你怀疑人生第三是遮挡严重工人之间互相遮挡、低头弯腰、被设备挡住半边身体都是常态。这些特点决定了我们需要的不是一个“能分类图片”的模型而是一个能在复杂背景下高效定位“人”和“安全帽”这类小目标的目标检测模型。传统视觉方案比如用OpenCV做肤色检测、轮廓匹配、颜色直方图在固定场景、固定角度下也许能跑通但只要换一个工地、换一个摄像头视角阈值立马失效维护成本极高。深度学习目标检测模型则不一样它通过大量标注数据自动学习“人”和“安全帽”的外观特征、上下文关系对不同环境的适应性强很多。而在深度学习方案里YOLO系列是综合性价比最高的选择。1.2 目标检测算法选型对比我最初调研过几类方案。两阶段检测的典型代表是Faster R-CNN精度确实高但速度太慢嵌入式设备上根本跑不动现场也没有人会配昂贵的GPU服务器单阶段的SSD速度上来了但小目标检测能力一般安全帽在画面里常常只有几十个像素容易漏检YOLO系列从第一代到现在的YOLOv8/v11一直在速度和精度之间做平衡特别是YOLOv8开始内置了Anchor-Free设计对小目标和密集场景更友好而且Ultralytics官方把训练、验证、导出、推理全都封装成了简单API对Python开发者来说极度友好。还有一个现实因素后期维护。YOLO的生态太成熟了网上有海量的预训练权重、教程、数据集格式转换工具。如果在工地上出现某个环境下的检测效果不好我可以快速用新数据微调而不是从零写网络。选型不只是选模型还是选整个生态和社区支撑。1.3 YOLO版本选择具体到版本我用的是YOLOv8更准确说是ultralytics库里的yolov8n和yolov8s。为什么不选最新的YOLO v11或者v12因为针对安全帽这种相对简单、类别固定的任务YOLOv8已经完全够用v8的API文档、社区问题沉淀、第三方示例都最丰富遇到问题往往搜索几个关键词就能找到解决方案对项目的稳定落地更重要。如果你做更复杂的场景比如同时检测安全帽、反光衣、抽烟、打电话再考虑升级到更新版本也不迟。实际测试时yolov8n在GPU上能跑到200FPS在CPU上也能有20-30FPS检测一张图片大约十几毫秒。yolov8s的mAP比n版高2到3个百分点但速度有所下降。我最终选择了yolov8s作为基础模型因为工地现场不差CPU那点算力准确性优先。2. 数据准备与模型训练2.1 安全帽数据集来源与标注格式训练一个能用的安全帽检测模型数据质量比模型结构更重要。我的数据主要来自两个渠道一是公开的安全帽数据集比如SHWDSafety Helmet Wearing Dataset它包含了大量工地场景下的图片标注类别是“person”戴安全帽的人的整体框和“helmet”安全帽框这个数据集有几千张图片适合做预训练和冷启动二是自己实地拍摄的工地照片用手机在白天、晚上、阴天、晴天各种时段拍再人工标注。公开数据集的标注格式通常不是YOLO格式需要转换。YOLO格式的标签是每个图片对应一个同名.txt文件每一行代表一个目标格式是类别id 中心点x 中心点y 宽度w 高度h其中坐标数值必须归一化到0到1之间。转换脚本并不复杂我用Python写了一个小工具把XML或者JSON格式的标注读进来再归一化输出成TXT批量处理目录下所有文件。如果你不会写可以用LabelImg或者Ultralytics自带的标注工具重新标注一轮只是成本高一些。2.2 数据增强与样本平衡训练数据里最大的坑是正负样本不平衡。我刚开始只用了SHWD数据集结果模型在模拟环境下表现不错一上真实工地就疯狂漏检原因是真实工地的角度、光照、分辨率完全不一样。后期补充数据时重点增加了三类样本一是远距离小目标样本保证画面中人物很小时也能框出来二是反光、逆光样本避免暗部人物全黑丢失三是遮挡样本比如工人弯腰抬钢筋安全帽只露出一个边。数据增强方面ultralytics默认开启了很多增强策略包括随机翻转、缩放、色彩抖动、马赛克增强Mosaic。这些默认策略对工地场景帮助极大尤其是马赛克增强它会把四张训练图拼在一起相当于模拟了更复杂的画面让模型学会在杂乱环境里检测目标。不过要注意一点默认增强中hsv_h、hsv_s这些色彩增强参数在有些光照极端的场景下会把安全帽颜色改得不像样子我训练时把hsv_h从默认的0.015调低到0.005保证黄色安全帽的颜色特征不被过度扭曲。2.3 训练参数配置与过程使用ultralytics训练非常简单准备一个data.yaml文件内容示例如下train: datasets/helmet/train/images val: datasets/helmet/val/images nc: 2 names: [helmet, person]这里有个容易踩坑的地方类别顺序。我一开始把help放在了索引1person放在索引0结果推理时框的颜色、后处理逻辑全乱了后来统一改成helmet在前、person在后并用num_classes2重新训练问题解决。建议在任何项目开始前就固定好类别顺序不要中途修改。训练命令yolo detect train datadata.yaml modelyolov8s.pt epochs100 imgsz640 batch16 device0训练轮次我建议别太少也不要太多。我用100轮大约训练了2个小时单张RTX 3060。如果发现验证集mAP不再提升就提前停止。训练过程中可以通过TensorBoard或者ultralytics自带的日志观察train/loss和val/obj_loss曲线如果训练损失下降但验证损失不降反升说明过拟合了这时候要加大patience或者降低模型复杂度。2.4 模型评估与导出训练完成后在验证集上评估我得到的mAP50约0.94mAP50-95约为0.78对于安全帽检测这种任务已经足够。不要只看mAP还要看每类的精确率Precision和召回率Recall。安全帽检测最怕的是漏检把没戴的看成戴了这会直接造成安全隐患相比之下误报把戴了的安全帽看成没戴危害小一些但太多误报也会让工作人员失去对系统的信任。所以调参时我会适当提高置信度阈值一般设置为0.35到0.45之间减少误报同时保留足够的召回。模型训练好后导出成ONNX格式方便部署yolo export modelbest.pt formatonnx dynamicTrue如果只在本机用直接用PyTorch权重best.pt就行加载速度快推理也简单。导出ONNX主要是为了以后做跨平台部署或者用TensorRT加速。3. 检测与预警核心实现3.1 图片检测的实现使用ultralytics进行图片检测的代码非常简洁from ultralytics import YOLO model YOLO(best.pt) results model.predict(site_photo.jpg, conf0.4, saveTrue, save_txtTrue, classes[0, 1])classes[0, 1]的意思是只检测已经在模型里定义的类别避免输出其他杂项。save_txtTrue会把每个目标的坐标保存下来方便后续统计。图片检测适合做离线巡检比如把工地所有的抓拍图片批量跑一遍生成一份未戴安全帽的清单。如果你需要识别单张图片并绘制检测框可以手动遍历resultsfor result in results: boxes result.boxes for box in boxes: cls int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() print(类别:, model.names[cls], 置信度:, conf, 坐标:, xyxy)3.2 视频流与实时摄像头检测视频流检测的核心就是不断读取视频帧送给模型推理再把结果画到帧上最后用OpenCV显示或推送。为了兼顾流畅性和检测效果我通常会把视频流分辨率降到640左右并且用threading或queue做异步处理避免因为模型推理阻塞画面显示。代码如下import cv2 import threading import queue from ultralytics import YOLO model YOLO(best.pt) cap cv2.VideoCapture(rtsp://your_stream_address) frame_queue queue.Queue(maxsize2) def process_frames(): while True: if not frame_queue.empty(): frame frame_queue.get() results model(frame, conf0.4, verboseFalse) # 处理结果画框 annotated results[0].plot() cv2.imshow(Helmet Detection, annotated) if cv2.waitKey(1) 0xFF ord(q): break threading.Thread(targetprocess_frames, daemonTrue).start() while True: ret, frame cap.read() if not ret: break if frame_queue.full(): try: frame_queue.get_nowait() except queue.Empty: pass frame_queue.put(frame)我遇到的一个典型性能问题用cv2.waitKey(1)后画面卡顿。后来发现是线程里频繁调用imshow而主线程读帧也在同时进行两者会争抢GIL。改用双队列、把imshow放在读取线程里可以明显改善。如果你追求极致流畅可以考虑直接把推理结果放在queue里由单独的显示线程去绘制形成“采集-推理-显示”三线程模型。3.3 安全帽未佩戴预警逻辑预警逻辑是整个系统的灵魂。模型输出里同时包含helmet和person两类目标但我们真正要判断的是画面中的每一个人是否戴了安全帽。这里有个关键点helmet和person并不是一对一绑定的。模型只是检测出所有安全帽框和所有人框你需要用几何关系去匹配——如果一个人框内部或其头部区域存在安全帽框就认为这个人戴了安全帽否则认为未佩戴。判断方法可以很粗暴计算安全帽框中心点是否落在人框的上半部分约人框高度的前30%之内。我实现了一版效果足够def is_helmet_present(person_box, helmet_boxes): px1, py1, px2, py2 person_box head_area (px1, py1, px2, py1 (py2 - py1) * 0.3) for hx1, hy1, hx2, hy2 in helmet_boxes: hcx (hx1 hx2) / 2 hcy (hy1 hy2) / 2 if head_area[0] hcx head_area[2] and head_area[1] hcy head_area[3]: return True return False还有一种思路是单独训练一个分类模型判断人是否戴帽但那样多一个模型部署复杂。基于空间关系的启发式方法在工程上简单有效。预警规则可以这样定义连续3帧中同一人通过IoU跟踪持续被判定为未戴安全帽才触发预警。这样可以避免人走动时帽子遮挡造成的瞬间误判。预警触发后做三件事界面警告文字变红并闪烁蜂鸣器或播放提示音Python里可以用winsound或pyaudio播放把当前帧保存到violations/时间戳.jpg目录并记录JSON日志方便后续生成报表。3.4 预警消息推送如果系统要接入现场管理可以把预警信息通过HTTP POST推送到服务器或者写入本地SQLite数据库。我为了快速落地只做了本地日志界面提示截图三件套。简单够用现场安全员不用额外学习复杂系统。后续如果要做手机远程提醒可以加一条requests.post到企业微信群机器人Webhook这个扩展起来也不难。4. 界面开发让非技术人员也能用4.1 界面选型PyQt5 vs Tkinter vs Web项目既然要求“有界面”那就要认真选GUI框架。我第一反应是TkinterPython自带简单但做实时视频显示和自定义控件样式很费劲而且刷新率高时界面容易卡顿。后来换成PyQt5虽然多引入一个依赖但功能完整用QLabel显示视频帧、用QThread做后台推理都不会卡界面。如果你更熟悉Web前端也可以用Flask/FastAPI Canvas实现网页界面但这样的部署对工地现场要求更高——现场往往只有一台Windows电脑打开一个本机exe比打开浏览器输IP方便得多。所以我最终选了PyQt5。核心思路是主窗口包含一个视频显示区域、一个实时状态栏、几个功能按钮开始检测、暂停、拍照、退出。把所有耗时操作包括视频读取和YOLO推理放在QThread子线程中通过信号emit把渲染好的QImage传给主线程更新界面。4.2 界面布局与功能拆解界面主要拆成四个区域左侧大区域显示摄像头或视频文件的实时画面检测框和预警文字直接绘制在上面。右侧信息面板显示实时检测帧率FPS、当前总人数、戴帽人数、未戴帽人数、最近一次预警时间。底部按钮区开始/停止检测、抓拍当前画面、打开历史预警记录。预警状态区一个颜色块正常为绿色触发预警时变为红色并闪烁。这些功能都不复杂但组合起来非常贴合现场需求。现场操作员文化水平参差不齐界面必须直观。按钮用大图标预警时红底白字“未佩戴安全帽”比复杂报表有效得多。4.3 关键代码PyQt5中显示YOLO检测结果在PyQt5的QThread里跑推理并通过信号把图像传送回来import cv2 from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtGui import QImage, QPixmap from ultralytics import YOLO class VideoThread(QThread): change_pixmap_signal pyqtSignal(QImage) warning_signal pyqtSignal(bool, int) def __init__(self): super().__init__() self.model YOLO(best.pt) self._running True def run(self): cap cv2.VideoCapture(0) while self._running: ret, frame cap.read() if not ret: continue results self.model(frame, conf0.4, verboseFalse) annotated results[0].plot() # 统计人数 total len(results[0].boxes) no_helmet self.count_no_helmet(results[0]) self.warning_signal.emit(no_helmet 0, total) rgb_image cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB) h, w, ch rgb_image.shape bytes_per_line ch * w qt_image QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888) self.change_pixmap_signal.emit(qt_image) cap.release()主界面里连接信号self.video_thread.change_pixmap_signal.connect(self.update_image) self.video_thread.warning_signal.connect(self.update_warning) def update_image(self, qimage): self.image_label.setPixmap(QPixmap.fromImage(qimage).scaled(self.image_label.size(), Qt.KeepAspectRatio)) def update_warning(self, has_violation, total): if has_violation: self.warning_label.setStyleSheet(background-color: red; color: white;) self.warning_label.setText(未佩戴安全帽) else: self.warning_label.setStyleSheet(background-color: green; color: white;) self.warning_label.setText(正常) self.count_label.setText(f检测人数: {total})这段代码的核心价值在于把推理和界面分离到不同线程避免界面卡死。实际运行中哪怕模型推理需要50毫秒界面依然流畅显示。5. 项目落地中的常见问题与排查5.1 误报/漏报问题做安全帽检测最怕的两种糟糕表现一是没戴帽子没警告漏报二是明明戴了帽子却报警误报。我排查出来的原因主要有三类。第一类数据分布覆盖不足。如果训练集中的安全帽都是正着戴的工人歪戴帽子时模型可能检测不到。解决方法是增加歪戴、反戴、帽檐遮挡的样本。第二类锚框匹配问题。对于YOLOv8这种Anchor-Free模型影响不大但如果你用YOLOv5小目标检测效果差一般需要把imgsz从640提高到1280或者调整anchors。第三类置信度阈值设置不合理。阈值太高容易漏报太低容易误报。我的做法是先在实际视频上跑一遍观察未戴帽子的置信度分布和误报样本的置信度分布取两者分离度最大的点。5.2 实时性优化如果发现视频流检测卡顿、延迟高优先排查这几个地方是否使用了GPU推理。如果只有CPU建议把输入尺寸降到imgsz480或换yolov8n模型。视频流分辨率是否过高。1080p的视频每帧都要跑模型压力太大。可以先用cv2.resize把帧缩放到640宽再推理检测框坐标再映射回原图这样精度损失极小但速度提升明显。是否频繁打印日志。推理循环中如果每帧都print会拖慢好几倍建议关掉verbose或只打印统计信息。摄像头读取和推理是否在同一线程。通过队列解耦后延迟能降低一半以上。5.3 部署注意事项把Python项目部署到工地电脑上通常需要打包成exe。我用PyInstaller打包最常遇到的问题就是缺少ultralytics的附加数据文件导致打包后模型加载报错。解决办法是在spec文件里手动添加ultralytics的数据路径a Analysis([main.py], datas[(best.pt, .), (your_data_dir, your_dest_dir)], ...)另外工地电脑可能没有NVIDIA驱动打包时最好带上CPU版本的PyTorch避免在无GPU机器上出现CUDA错误。如果你不确定现场环境直接用devicecpu推理比较省心只是速度慢一些。5.4 常见问题速查表问题现象可能原因解决办法模型加载很慢权重文件大、CPU模式用yolov8n量化或转ONNX后使用预览画面卡顿推理和显示互相阻塞用多线程队列解耦检测不到小目标imgsz太小提高到960或1280或增加小目标样本不戴帽的人没框出置信度阈值过高调低到0.3试一下戴帽的人被误报安全帽框匹配逻辑错误检查头盔框是否落在头部区域拍摄视频无法打开编码格式不支持用OpenCV的Videocapture重编码或用ffmpeg转码PyInstaller打包后找不到模型模型文件路径不对使用sys._MEIPASS获取资源路径6. 扩展方向与个人体会如果你已经能跑通这套系统想再进一步可以从几个方向扩展。可以把“未戴安全帽”的人员跟踪起来比如接入ByteTrack统计每个未戴帽人员在画面里出现的时间生成更细的违规记录。也可以把安全帽检测和抽烟检测、反光衣检测、区域入侵检测整合到同一个YOLO模型里一次性完成多种安全行为分析。算法层面工地场景往往有固定的摄像头机位可以针对每个机位做视角矫正提高检测精度还可以结合工地考勤系统识别到未戴帽的人后联动道闸禁止进入。我现在维护的这套系统后来又加了“车辆识别”和“铲车离人报警”功能。从安全帽出发慢慢把一个孤立的检测程序变成工地现场的多维安全卫士。根据我个人经验做这类项目最大的心得是不要一开始就追求SOTA模型、复杂架构先把一个最小闭环跑通再根据真实反馈迭代。安全和准确是首位界面华丽是次要的。如果你也准备做强烈建议先收集半个月现场的视频数据再训练第一版模型这样模型一上线就能用而不是在实验室里自嗨。本文还有配套的精品资源点击获取