-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsocial_distancing.py
216 lines (160 loc) · 6.92 KB
/
social_distancing.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# -*- coding: utf-8 -*-
"""Social_Distancing.ipynb
Automatically generated by Colaboratory.
Original file is located at
https://colab.research.google.com/drive/1Q9X9hlElvGidGHRm0M9Nd3odykew55Nb
"""
#Base Path to YOLO directory
MODEL_PATH = "yolo-coco"
MIN_CONF = 0.3 #Initializing Minimum probability to filter weak detections
NMS_THRESH = 0.3 # To Remove redundant bounding boxes in object detection
USE_GPU = False
MIN_DISTANCE = 50 # Minimum safe distance between two people in pixels
import numpy as np # NUmPy is an array processing package
import cv2 #Opencv library for image processing
def detect_people(frame, net, ln, personIdx=0):
#grab the dimenions of the frame
(H, W) = frame.shape[:2]
# Initializing the Result list
results = []
# the below method is used to generate a 4-dimensional array(blob) of image-frame
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416),
swapRB=True, crop=False)
net.setInput(blob)
#performing a forward pass of the YOLO object detector, resulting in bounding boxes and associated probabilities
layerOutputs = net.forward(ln)
#Initializing the lists for boxes, centroids and confidences
boxes = []
centroids = []
confidences = []
#Running loop over layeroutputs for output
for output in layerOutputs:
#Running loop over output for detections
for detection in output:
#Extracting the class ID and confidence of the current object detected
scores = detection[5:]
classID = np.argmax(scores)
confidence = scores[classID]
#Filtering detections by ensuring that the detected object is person
# checking whether Minimum confidence is met or not
if classID == personIdx and confidence > MIN_CONF:
#scaling the bounding box coordinates relative to image size
box = detection[0:4] * np.array([W, H, W, H])
(centerX, centerY, width, height) = box.astype("int")
#Making use of (x,y) coordinates to derive the corners of bounding box
x = int(centerX - (width / 2))
y = int(centerY - (height / 2))
#Updating the lists
boxes.append([x, y, int(width), int(height)])
centroids.append((centerX, centerY))
confidences.append(float(confidence))
#Applying Non-Maxima suppression to remove weak and overlapping bounding boxes
idxs = cv2.dnn.NMSBoxes(boxes, confidences, MIN_CONF, NMS_THRESH)
#checking whether atleast one detection exists or not
if len(idxs) > 0:
#looping over indexes
for i in idxs.flatten():
#Extracting Bounding box coordinates
(x, y) = (boxes[i][0], boxes[i][1])
(w, h) = (boxes[i][2], boxes[i][3])
#Updating result list to include Person prediction Probability, Bounding box coordinates and centroids
r = (confidences[i], (x, y, x + w, y + h), centroids[i])
results.append(r)
return results
#Importing Necessary Packages
from google.colab.patches import cv2_imshow
from scipy.spatial import distance as dist
import numpy as np
import argparse
import imutils
import cv2
import os
#Constructing the argument parser and parsing the inputs
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(["--input","/content/drive/MyDrive/SocialDistancing/pedestrians1.mp4","--output","my_output.avi","--display","1"]))
#Loading the CoCo class labels on which Yolo was trained on
labelsPath = os.path.sep.join(["/content/drive/MyDrive/SocialDistancing/coco.names"])
LABELS = open(labelsPath).read().strip().split("\n")
#Deriving the path of Yolo weights
weightsPath = os.path.sep.join(["/content/drive/MyDrive/SocialDistancing/yolov3.weights"])
#Deriving the path of model configuration
configPath = os.path.sep.join(["/content/drive/MyDrive/SocialDistancing/yolov3.cfg"])
#Loading thhe Yolo object detector.
print("[INFO] loading YOLO from disk...")
net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)
#Determining the output layer names that we need from Yolo
ln = net.getLayerNames()
ln = [ln[i - 1] for i in net.getUnconnectedOutLayers()]
#Initializing the video stream and pointer to output video file
print("[INFO] accessing video stream...")
vs = cv2.VideoCapture(args["input"] if args["input"] else 0)
writer = None
#Looping over the frames from the video stream
while True:
#Grabbing the Frames from the video file
(grabbed, frame) = vs.read()
#breaking the loop, if the frame is not grabbed, It shows that we have reached the end
if not grabbed:
break
#Resizing the Frame
frame = imutils.resize(frame, width=700)
#Detecting only people
results = detect_people(frame, net, ln,
personIdx=LABELS.index("person"))
#creating a set of indexes that violate the minimum social distance
violate = set()
#checking atleast two people are in frame or not to compute distance
if len(results) >= 2:
#Extracting all centroids from results
centroids = np.array([r[2] for r in results])
#Computing Euclidean distances between all pairs of centroids
D = dist.cdist(centroids, centroids, metric="euclidean")
#Looping over the Distance matrix
for i in range(0, D.shape[0]):
for j in range(i + 1, D.shape[1]):
#checking if the distance between any 2 centroids is less than Min_Distance
if D[i, j] < MIN_DISTANCE:
#Updating Violation set with indexes of centroid pairs
violate.add(i)
violate.add(j)
for (i, (prob, bbox, centroid)) in enumerate(results):
#Extracting the bounding boxes
(startX, startY, endX, endY) = bbox
#Extracting the centroid coordinates
(cX, cY) = centroid
#Initializing the color of annotation
color = (0, 255, 0)
#Updating the color if index pair exixts in violation set
if i in violate:
color = (0, 0, 255)
#Drawing bounding boxes around the person
cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2)
#Drawing centroid coordinates of the person
cv2.circle(frame, (cX, cY), 5, color, 1)
#Drawing the total number of violations on the output frame
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)
#checking whether it's required to display the output frame on screen
if args["display"] > 0:
#To show the output frame
cv2_imshow(frame)
key = cv2.waitKey(1) & 0xFF
#Break the loop if "q" is pressed
if key == ord("q"):
break
#If output video file path is given but video writer has not been initialized, then doing in now using below commands
if args["output"] != "" and writer is None:
#Initializing 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:
#if the VideoWriter is not none, write the frame to the output video file
writer.write(frame)