使用单目摄像头,通过相似三角形原理进行测距,部分代码如下,使用yolov3做人体识别。可以完成对在场所有人是否小于预设的社交距离的判断以及是否佩戴口罩
口罩佩戴的判断使用的是百度飞桨的paddlehub模型,具体可以在官网查到相关资料
部分代码如下
from TheLazyCoder import social_distancing_config as config
from TheLazyCoder.detection import detect_people
from scipy.spatial import distance as dist
import numpy as np
import argparse
import imutils
import cv2
import os
import paddlehub as hub
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input", type=str, default="",
help="path to (optional) input video file")
ap.add_argument("-o", "--output", type=str, default="",
help="path to (optional) output video file")
ap.add_argument("-d", "--display", type=int, default=1,
help="whether or not output frame should be displayed")
args = vars(ap.parse_args())
#导入口罩模型
mask_detector = hub.Module(name="pyramidbox_lite_server_mask")
#载入yolo的模型和标签
labelsPath = os.path.sep.join([config.MODEL_PATH, "coco.names"])
LABELS = open(labelsPath).read().strip().split("n")
# 导入权重
weightsPath = os.path.sep.join([config.MODEL_PATH, "yolov3.weights"])
configPath = os.path.sep.join([config.MODEL_PATH, "yolov3.cfg"])
# 加载在coco训练集上的对象检测器
print("[INFO] loading YOLO from disk...")
net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)
# check if we are going to use GPU
if config.USE_GPU:
# set CUDA as the preferable backend and target
print("[INFO] setting preferable backend and target to CUDA...")
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
# 仅确定我们需要YOLO提供的*输出*图层名称
ln = net.getLayerNames()
ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]
# 初始化视频流和指向输出视频文件的指针
print("[INFO] accessing video stream...")
vs = cv2.VideoCapture(args["input"] if args["input"] else 0)
writer = None
# 循环播放视频帧
while True:
# read the next frame from the file
(grabbed, frame) = vs.read()
cv2.imwrite("1.jpg",frame)
result = mask_detector.face_detection(images=[cv2.imread('1.jpg')])
print(result[0]['data'][0]['label'])
#如果没框架了,说明视频已经到末尾
if not grabbed:
break
# 调整框架大小,仅检测画面中的人
frame = imutils.resize(frame, width=700)
results = detect_people(frame, net, ln,
personIdx=LABELS.index("person"))
# 初始化违反社交距离的最小距离
violate = set()
#确保画面至少两人,以计算所有成对对象间的距离
if len(results) >= 2:
# 从结果中提取所有质心并计算所有质心对之间的欧氏距离
centroids = np.array([r[2] for r in results])
D = dist.cdist(centroids, centroids, metric="euclidean")
#距离矩阵上三角的计算
for i in range(0, D.shape[0]):
for j in range(i + 1, D.shape[1]):
#检查任意两个质心间的距离是否小于配置的像素点
if D[i, j] < config.MIN_DISTANCE:
# 更新质心对
violate.add(i)
violate.add(j)
# 循环查看结果
for (i, (prob, bbox, centroid)) in enumerate(results):
# 画框
(startX, startY, endX, endY) = bbox
(cX, cY) = centroid
color = (0, 255, 0)
# 如果索引对象存在于冲突集,则更新边框颜色
if i in violate:
color = (0, 0, 255)
# 人周围画框,质心画圆圈
cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2)
cv2.circle(frame, (cX, cY), 5, color, 1)
# 显示违反社交距离的人员总数
text = "Social Distancing Violations: {}".format(len(violate))
cv2.putText(frame, text, (10, frame.shape[0] - 25),
cv2.FONT_HERSHEY_SIMPLEX, 0.85, (0, 0, 255), 3)
# 检查输出帧是否显示到屏幕
if args["display"] > 0:
# show the output frame
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
# 视频初始化
if args["output"] != "" and writer is None:
# initialize our video writer
fourcc = cv2.VideoWriter_fourcc(*"MJPG")
writer = cv2.VideoWriter(args["output"], fourcc, 25,
(frame.shape[1], frame.shape[0]), True)
if writer is not None:
writer.write(frame)



