使用单目摄像头,通过相似三角形原理进行测距,部分代码如下,使用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)
MODEL_PATH = "yolo-coco"
# initialize minimum probability to filter weak detections along with
# the threshold when applying non-maxima suppression
#初始化最小概率以过滤弱检测以及
#应用非最大值抑制时的阈值
MIN_CONF = 0.3
NMS_THRESH = 0.3
# boolean indicating if NVIDIA CUDA GPU should be used
USE_GPU = False
# define the minimum safe distance (in pixels) that two people can be
# from each other
MIN_DISTANCE = 195
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
import requests
import time
import base64
def peoplenum(pics,nums):
login_url = "https://xiyoulvma.xyz/weixin/flow" # 请求地址
url = login_url # 拼接地址
# 参数
body1 = {'pic': pics,
'num': nums,
}
# 发送请求
r = requests.post(url=url, json=body1)
print(r)
def wechat(num): #向微信发送东西
url = ' https://api.bemfa.com/api/wechat/v1/weget.php'
data = {
'uid': 'dde0bd25d9e142acaf7a126aadcf906a',
'type': '1',
'device': '邮电大学0号车',
'msg': '此处有违法社交距离及未佩戴口罩情况发生,人数为:'+ str(num)
}
response = requests.get(url, data)
print(response.text)
def live_get():
login_url = "https://open.ys7.com/api/lapp/token/get" # 请求地址
url = login_url # 拼接地址
# 参数
body1 = {'appKey': '394a0e460c504daab84d71079b59adcc',
'appSecret': '14f3dcbba15c3fccc2a218b55cc420d2',
}
# 发送请求
r = requests.post(url=url, params=body1).json()
# 输出返回
live_url = "https://open.ys7.com/api/lapp/v2/live/address/get" # 请求地址
body2 = {'accessToken': r['data']['accessToken'],
'deviceSerial': 'J22672477',
'protocol': 2,
}
r = requests.post(url=live_url, params=body2).json()
# 输出返回
return r['data']['url']
# 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- 1] for i in net.getUnconnectedOutLayers()]
# 初始化视频流和指向输出视频文件的指针
#vs = cv2.VideoCapture(live_get())
vs = cv2.VideoCapture(0)
writer = None
tot = 1
# 循环播放视频帧
while True:
flag=1
# read the next frame from the file
(grabbed, frame) = vs.read()
if grabbed == True:
if tot>0:
cv2.imwrite("1.jpg", frame)
img = cv2.imread("1.jpg")
with open("/home/bj/socialdistance/1.jpg", "rb") as f:
pic1 = f.read()
pic1=str(base64.b64encode(pic1))
#如果没框架了,说明视频已经到末尾
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)>0):
try:
resultt = mask_detector.face_detection(images=[img])
except:
pass
#确保画面至少两人,以计算所有成对对象间的距离
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)
if (len(resultt[0]['data']) != 0):
for i in range(len(resultt[0]['data'])):
if resultt[0]['data'][i]['label'] == 'NO MASK':
cv2.putText(frame, resultt[0]['data'][i]['label'],
(resultt[0]['data'][i]['left'] - 20, resultt[0]['data'][i]['top'] - 25),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
else:
cv2.putText(frame, resultt[0]['data'][i]['label'],
(resultt[0]['data'][i]['left'] - 20, resultt[0]['data'][i]['top'] - 25),
cv2.FONT_HERSHEY_SIMPLEX, 0.5,
(0, 255, 0), 2)
cv2.rectangle(frame, (resultt[0]['data'][i]['left'] - 20, resultt[0]['data'][i]['top'] - 20),
(resultt[0]['data'][i]['right'] + 20, resultt[0]['data'][i]['bottom'] + 20),
(200, 200, 40), 2)
# 显示违反社交距离的人员总数
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(len(violate)>=2 and flag == 1):
flag = 0
wechat(len(violate))
peoplenum(pic1, len(results))
# 检查输出帧是否显示到屏幕
if args["display"] > 0:
# show the output frame
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
else:
time.sleep(0.03)
frame = imutils.resize(frame, width=700)
cv2.imshow("Frame", frame)
flag = 1
cv2.waitKey(1)
tot+=1
if tot >= 204:
tot=0
else:
vs = cv2.VideoCapture(0)
(grabbed, frame) = vs.read()
vs.release()
cv2.destroyAllWindows()
在这里插入代码片