1. 项目概述
在建筑工地等高风险作业环境中,工人安全帽的正确佩戴是保障施工人员生命安全的基本要求。传统的人工巡检方式存在效率低下、覆盖范围有限、容易出现人为疏忽等问题。针对这一痛点,我们设计并实现了一套基于图像处理与深度学习的工人安全作业监测系统。
这套系统采用改进的YOLOv8-MEU算法,能够实时、准确地检测工人的安全帽佩戴状态。系统支持三种主要检测模式:
- 图片检测:支持单张或批量图片的安全帽佩戴状态分析
- 视频检测:可对视频文件进行逐帧分析
- 实时监测:通过摄像头实时监控作业现场
系统核心优势在于:
- 检测准确率高:在测试集上达到96.2%的mAP
- 实时性能好:在普通GPU上可实现45FPS的处理速度
- 适应性强:能够应对复杂光照、遮挡等现场环境
2. 系统架构设计
2.1 整体架构
系统采用模块化设计,主要包含以下组件:
code复制┌───────────────────────────────────────────────────────┐
│ Worker Safety Monitoring System │
├───────────────┬───────────────┬───────────────┬───────┤
│ User Auth │ Media File │ Real-time │ Data │
│ Module │ Detection │ Monitoring │ Mgmt. │
└───────────────┴───────────────┴───────────────┴───────┘
│ │ │ │
▼ ▼ ▼ ▼
┌───────────────────────────────────────────────────────┐
│ YOLOv8-MEU Detection Model │
└───────────────────────────────────────────────────────┘
2.2 技术选型考量
在选择系统技术方案时,我们主要考虑了以下几个关键因素:
-
实时性要求:工地监控需要实时响应,因此选择了YOLO系列的单阶段检测算法而非两阶段算法(如Faster R-CNN)
-
部署环境限制:考虑到工地现场可能没有高性能计算设备,我们特别注重模型的轻量化
-
检测目标特性:安全帽通常是小目标,且可能被部分遮挡,需要算法具备良好的小目标检测能力
-
系统扩展性:需要支持多种输入源(图片/视频/摄像头)和灵活的功能扩展
基于这些考量,我们最终确定了以改进YOLOv8为核心的技术路线。
3. 核心算法实现
3.1 YOLOv8-MEU模型架构
我们对标准YOLOv8模型进行了三处关键改进:
-
轻量级主干网络:用MobileNetV3-Small替换原主干网络
- 参数量减少62%(从6.3M降至2.4M)
- 计算量降低58%(从15.8GFLOPs降至6.6GFLOPs)
- 保留SPPF模块处理多尺度特征
-
ECA注意力机制:在特征提取后加入轻量级通道注意力
- 自适应计算卷积核大小
- 仅增加0.2M参数
- 提升小目标检测准确率3.5%
-
EIoU损失函数:改进边界框回归
- 同时考虑重叠面积、中心点距离和宽高比
- 定位精度提升2.1%
模型完整架构如下:
python复制class YOLOv8MEU(nn.Module):
def __init__(self, num_classes=2, pretrained=True):
super(YOLOv8MEU, self).__init__()
# 轻量级主干网络
self.backbone = MobileNetV3Small(pretrained=pretrained)
self.backbone.layers = nn.Sequential(*list(self.backbone.layers.children())[:-4])
# 多尺度特征处理
self.sppf = SPPF(in_channels=576, out_channels=576)
# 注意力机制
self.eca = ECA(in_channels=576)
# 特征融合网络
self.fpn_pan = FPNPAN(in_channels=[160, 240, 576])
# 检测头
self.head = DecoupledHead(num_classes=num_classes, in_channels=256)
3.2 关键组件实现
3.2.1 ECA注意力机制
ECA模块通过轻量级的一维卷积实现通道间信息交互:
python复制class ECA(nn.Module):
def __init__(self, in_channels, gamma=2, b=1):
super(ECA, self).__init__()
# 自适应计算卷积核大小
t = int(abs((math.log2(in_channels) + b) / gamma))
k = t if t % 2 else t + 1
self.conv = nn.Conv1d(1, 1, kernel_size=k, padding=(k-1)//2, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
# 全局平均池化
y = x.mean((2, 3), keepdim=True)
# 通道注意力计算
y = self.conv(y.squeeze(-1).transpose(-1, -2))
y = y.transpose(-1, -2).unsqueeze(-1)
# 生成注意力权重
y = self.sigmoid(y)
return x * y.expand_as(x)
3.2.2 EIoU损失函数
EIoU损失综合考虑了重叠率、中心点距离和宽高比:
python复制def eioU_loss(pred_boxes, target_boxes):
# 计算IoU
intersection = calculate_intersection(pred_boxes, target_boxes)
union = calculate_union(pred_boxes, target_boxes)
iou = intersection / (union + 1e-6)
# 中心点距离
pred_center = get_center(pred_boxes)
target_center = get_center(target_boxes)
center_distance = torch.pow(pred_center - target_center, 2).sum(dim=-1)
# 最小外接矩形
cw = torch.max(pred_boxes[:, 2], target_boxes[:, 2]) - torch.min(pred_boxes[:, 0], target_boxes[:, 0])
ch = torch.max(pred_boxes[:, 3], target_boxes[:, 3]) - torch.min(pred_boxes[:, 1], target_boxes[:, 1])
c = torch.pow(cw, 2) + torch.pow(ch, 2)
# 宽高损失
pred_width = pred_boxes[:, 2] - pred_boxes[:, 0]
pred_height = pred_boxes[:, 3] - pred_boxes[:, 1]
target_width = target_boxes[:, 2] - target_boxes[:, 0]
target_height = target_boxes[:, 3] - target_boxes[:, 1]
width_loss = torch.pow((target_width - pred_width) / (torch.max(target_width, pred_width) + 1e-6), 2)
height_loss = torch.pow((target_height - pred_height) / (torch.max(target_height, pred_height) + 1e-6), 2)
# 综合计算EIoU
eioU = iou - (center_distance / (c + 1e-6)) - width_loss - height_loss
return 1 - eioU.mean()
4. 数据集构建与训练
4.1 数据收集与标注
我们构建了包含7581张图像的数据集,主要来源包括:
- 网络爬取:从公开图片网站获取约4000张工地场景图片
- 视频截帧:从工地监控视频中提取约2500张关键帧
- 实地拍摄:在不同工地现场拍摄约1000张图片
标注规范:
- 标注整个头部区域(而非仅安全帽)
- 两类标签:helmet(佩戴安全帽)和head(未佩戴)
- 使用LabelImg工具进行标注,后转换为YOLO格式
4.2 数据增强策略
为提高模型泛化能力,采用了多种数据增强:
-
基础增强:
- 随机旋转(-15°~15°)
- 水平/垂直翻转
- 亮度/对比度调整
-
高级增强:
- Mosaic增强:四图拼接
- MixUp:两图混合
- 随机遮挡:模拟现场遮挡情况
-
针对性增强:
- 增加小目标样本(远距离拍摄)
- 添加噪声(模拟低光照条件)
4.3 模型训练细节
训练配置:
- 硬件:NVIDIA RTX 3090
- 优化器:AdamW (lr=0.001)
- 批次大小:32
- 训练轮次:300
- 学习率调度:Cosine退火
关键训练技巧:
- 预热训练:前10轮使用较低学习率(0.0001)
- 困难样本挖掘:针对分类困难样本增加权重
- 早停机制:连续15轮验证集mAP不提升则停止
训练曲线显示:
- 损失值在100轮后趋于稳定
- mAP在250轮左右达到峰值
- 最终模型在测试集上达到96.2%的mAP
5. 系统实现与部署
5.1 功能模块实现
5.1.1 用户认证模块
采用PyQt5实现GUI,SQLite存储用户数据:
python复制class LoginWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('安全监测系统登录')
self.resize(300, 200)
# 初始化数据库连接
self.conn = sqlite3.connect('users.db')
self.cursor = self.conn.cursor()
self.create_table()
# UI组件
self.username_label = QLabel('用户名:')
self.username_input = QLineEdit()
self.password_label = QLabel('密码:')
self.password_input = QLineEdit()
self.password_input.setEchoMode(QLineEdit.Password)
self.login_btn = QPushButton('登录')
self.register_btn = QPushButton('注册')
# 布局
layout = QVBoxLayout()
layout.addWidget(self.username_label)
layout.addWidget(self.username_input)
layout.addWidget(self.password_label)
layout.addWidget(self.password_input)
layout.addWidget(self.login_btn)
layout.addWidget(self.register_btn)
self.setLayout(layout)
# 信号连接
self.login_btn.clicked.connect(self.login)
self.register_btn.clicked.connect(self.register)
5.1.2 实时检测模块
基于OpenCV实现摄像头视频流处理:
python复制class VideoDetector:
def detect_realtime(self, camera_id=0):
cap = cv2.VideoCapture(camera_id)
while True:
ret, frame = cap.read()
if not ret:
break
start_time = time.time()
# 预处理
img = self.preprocess(frame)
# 模型推理
with torch.no_grad():
outputs = self.model(img)
# 后处理
result_frame = self.postprocess(frame, outputs, img.shape)
# 计算并显示FPS
fps = 1 / (time.time() - start_time)
cv2.putText(result_frame, f'FPS: {fps:.2f}', (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
cv2.imshow('安全帽检测', result_frame)
if cv2.waitKey(1) == 27: # ESC键退出
break
cap.release()
cv2.destroyAllWindows()
5.2 性能优化技巧
-
多线程处理:
- 视频采集和模型推理分离到不同线程
- 使用队列实现线程间通信
-
模型量化:
- 将FP32模型量化为INT8
- 推理速度提升1.8倍,精度损失<1%
-
内存优化:
- 重用中间缓冲区
- 及时释放不再使用的张量
-
硬件加速:
- 使用OpenCV的DNN模块
- 开启CUDA加速
6. 实际应用与效果评估
6.1 测试环境
我们在三个不同场景下测试了系统性能:
- 室内测试场:控制环境,理想光照
- 建筑工地:复杂光照,多人场景
- 工厂车间:金属反光,机械遮挡
6.2 性能指标
| 指标 | 测试场 | 建筑工地 | 工厂车间 |
|---|---|---|---|
| 准确率(%) | 98.7 | 95.2 | 93.8 |
| 召回率(%) | 97.5 | 94.1 | 92.3 |
| 平均处理时间(ms) | 18 | 22 | 25 |
| 漏检率(%) | 1.2 | 3.5 | 4.8 |
| 误检率(%) | 0.8 | 2.1 | 3.2 |
6.3 典型问题与解决方案
-
强光反射问题:
- 现象:金属安全帽在阳光下产生强烈反光
- 解决方案:在数据增强中添加模拟反光样本
-
遮挡问题:
- 现象:工人被脚手架部分遮挡
- 解决方案:改进损失函数,增强对部分可见目标的检测
-
小目标检测:
- 现象:远距离工人检测效果差
- 解决方案:增加小目标专用检测头
7. 扩展与改进方向
在实际部署过程中,我们发现系统还可以从以下几个方向进行改进:
- 多目标检测:扩展检测其他安全装备(安全带、防护眼镜等)
- 行为分析:检测危险行为(如攀爬、违规操作)
- 跨摄像头追踪:实现工人跨监控区域的行为追踪
- 边缘计算部署:优化模型以适应边缘设备部署
一个特别实用的改进是添加"安全区域分析"功能,可以检测工人是否进入了危险区域。这可以通过在现有系统中集成语义分割模型来实现:
python复制class SafetyZoneAnalyzer:
def __init__(self, seg_model_path):
self.seg_model = load_segmentation_model(seg_model_path)
def analyze(self, frame, bboxes):
# 获取分割结果
seg_map = self.seg_model.predict(frame)
# 检测每个工人是否在危险区域
violations = []
for box in bboxes:
if box['class'] == 'head': # 只检查未戴安全帽的工人
center = self.get_center(box)
if seg_map[center[1], center[0]] == DANGER_ZONE:
violations.append(box)
return violations
这套系统在实际工地部署后,客户反馈安全事故率降低了63%,安全检查效率提升了4倍。特别是在高空作业区域,系统能够及时发现未佩戴安全帽的工人并发出警报,有效预防了多起可能的安全事故。
