You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Yolo v4的工地人员安全帽与安全服佩戴状态检测实现方法问询

我来帮你一步步解决这个工地安全检测的需求,核心逻辑就是先完成三类目标的基础检测,再通过边界框关联判断人员的佩戴状态,最后完成个性化标注。下面是具体的实现思路和代码示例:

实现思路与步骤

1. 先明确YOLOv4检测结果的结构

不管你用Darknet原生框架还是Python封装的YOLOv4库(比如yolov4-tf或者OpenCV的DNN模块),每个检测目标的输出都会包含这些关键信息:

  • 边界框坐标:通常是(x1, y1, x2, y2),分别对应左上角和右下角的像素坐标
  • 类别ID(对应person/hat/vest)
  • 置信度(模型对这个检测结果的信任程度)

你在代码里可以直接从检测输出中提取这些数据,比如用OpenCV DNN的话,推理后会得到一个形状为[num_detections, 7]的数组,每一行是[x1, y1, x2, y2, confidence, class_id](不同库可能顺序略有差异,注意调整)。

2. 建立hat/vest与person的关联关系

要判断人员是否佩戴了安全帽和安全服,核心是把每个hat/vest匹配到对应的person。这里推荐两种简单高效的方法:

方法一:检查目标中心点是否在person的边界框内

因为安全帽肯定戴在人头上,安全服穿在人身上,它们的中心点大概率落在person的框内。具体步骤:

  • 计算每个hat/vest的中心点坐标:(cx = (x1+x2)/2, cy = (y1+y2)/2)
  • 对每个hat/vest,遍历所有person的框,判断person_x1 < cx < person_x2且person_y1 < cy < person_y2,满足条件就说明这个hat/vest属于该person。

方法二:计算IOU(交并比)

如果有轻微遮挡的情况,中心点可能出界,这时候可以计算hat/vest和person框的IOU,当IOU大于一个阈值(比如0.1)时,判定为关联。IOU的计算公式是:

def calculate_iou(box1, box2):
    # box1: (x1,y1,x2,y2), box2: (x1,y1,x2,y2)
    x_left = max(box1[0], box2[0])
    y_top = max(box1[1], box2[1])
    x_right = min(box1[2], box2[2])
    y_bottom = min(box1[3], box2[3])
    
    if x_right < x_left or y_bottom < y_top:
        return 0.0
    
    intersection_area = (x_right - x_left) * (y_bottom - y_top)
    box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1])
    box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1])
    iou = intersection_area / float(box1_area + box2_area - intersection_area)
    return iou

3. 判断佩戴状态并标注

拿到关联结果后,对每个person进行判断:

  • 如果同时匹配到hat和vest:标注person wearing hat and vest
  • 否则(缺其中一个或者都缺):标注person not wearing hat and vest

然后用OpenCV的putText和rectangle函数,把标签画在person的边界框上方或者内部。

代码示例(Python + OpenCV DNN)

这里给出一个简化的实现示例,假设你已经有训练好的YOLOv4权重、配置文件和类别名文件:

import cv2
import numpy as np

# 加载YOLOv4模型
net = cv2.dnn.readNet("yolov4-custom.weights", "yolov4-custom.cfg")
classes = []
with open("obj.names", "r") as f:
    classes = [line.strip() for line in f.readlines()]
layer_names = net.getLayerNames()
output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers()]

# 加载测试图像
img = cv2.imread("construction_site.jpg")
height, width, channels = img.shape

# 预处理图像
blob = cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, crop=False)
net.setInput(blob)
outs = net.forward(output_layers)

# 初始化存储变量
person_boxes = []
hat_boxes = []
vest_boxes = []
conf_threshold = 0.5
nms_threshold = 0.4

# 解析检测结果
for out in outs:
    for detection in out:
        scores = detection[5:]
        class_id = np.argmax(scores)
        confidence = scores[class_id]
        if confidence > conf_threshold:
            # 获取边界框坐标
            center_x = int(detection[0] * width)
            center_y = int(detection[1] * height)
            w = int(detection[2] * width)
            h = int(detection[3] * height)
            x1 = int(center_x - w / 2)
            y1 = int(center_y - h / 2)
            x2 = x1 + w
            y2 = y1 + h
            
            # 分类存储不同目标的框
            if classes[class_id] == "person":
                person_boxes.append({"box": (x1, y1, x2, y2), "has_hat": False, "has_vest": False})
            elif classes[class_id] == "hat":
                hat_boxes.append((x1, y1, x2, y2))
            elif classes[class_id] == "vest":
                vest_boxes.append((x1, y1, x2, y2))

# 关联hat到person
for hat in hat_boxes:
    cx = (hat[0] + hat[2]) / 2
    cy = (hat[1] + hat[3]) / 2
    for person in person_boxes:
        px1, py1, px2, py2 = person["box"]
        if px1 < cx < px2 and py1 < cy < py2:
            person["has_hat"] = True
            break  # 一个hat对应一个person,找到就跳出

# 关联vest到person
for vest in vest_boxes:
    cx = (vest[0] + vest[2]) / 2
    cy = (vest[1] + vest[3]) / 2
    for person in person_boxes:
        px1, py1, px2, py2 = person["box"]
        if px1 < cx < px2 and py1 < cy < py2:
            person["has_vest"] = True
            break

# 绘制标注
for person in person_boxes:
    x1, y1, x2, y2 = person["box"]
    # 画人员边界框
    cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
    # 确定标签文本
    if person["has_hat"] and person["has_vest"]:
        label = "person wearing hat and vest"
        label_color = (0, 255, 0)  # 绿色表示合规
    else:
        label = "person not wearing hat and vest"
        label_color = (0, 0, 255)  # 红色表示不合规
    # 绘制标签
    cv2.putText(img, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, label_color, 2)

# 显示结果
cv2.imshow("Construction Site Safety Detection", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

额外注意事项

  • 数据集与训练:确保你的训练数据集里,每个person对应的hat和vest标注准确,这样模型的检测精度才会高,关联判断才可靠。
  • 置信度与NMS阈值:根据实际场景调整conf_threshold和nms_threshold,避免误检或漏检。
  • 多目标匹配:如果一个person对应多个hat/vest(比如误检),可以选择置信度最高的那个进行匹配,或者增加IOU阈值过滤。

内容的提问来源于stack exchange,提问作者Othmane Chanaa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 13:52:31