基于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
相关产品推荐
相关产品推荐

