-
Notifications
You must be signed in to change notification settings - Fork 1
/
app.py
178 lines (140 loc) · 6.02 KB
/
app.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
import cv2
import numpy as np
from scipy.spatial import distance as dist
from flask import Flask, render_template, request
import os
app = Flask(__name__)
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
@app.route("/")
def index():
return render_template("upload.html")
@app.route("/upload", methods=['POST'])
def upload():
target = os.path.join(APP_ROOT, 'videos/')
print(target)
if not os.path.isdir(target):
os.mkdir(target)
for file in request.files.getlist('file'):
print(file)
filename = "video.mp4"
destination = "/".join([target, filename])
print(destination)
file.save(destination)
# Initialize video stream
cap = cv2.VideoCapture('./videos/video.mp4')
# Initializing threshold values
confThreshold = 0.3
nmsThreshold = 0.3
MinDist = 60
# Importing coco.names dataset and storing the names in a list
classesFile = './yolo-coco/coco.names'
classNames = []
with open(classesFile, 'rt') as f:
classNames = f.read().rstrip('\n').split('\n')
# print(classNames)
# Path to YOLOv3 model config and weights file
modelConfiguration = './yolo-coco/yolov4-tiny.cfg'
modelWeights = './yolo-coco/yolov4-tiny.weights'
# Setting the model
net = cv2.dnn.readNetFromDarknet(modelConfiguration, modelWeights)
# Setting backend and target
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
# Not using CUDA
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
def find_objects(img, net, ln, personIdx=0):
(ht, wt) = img.shape[:2]
# print(ht,wt)
# To store person prediction probability, bbox coordinates and centroid of object
results = []
# Convert image frames to blob to feed into the model
blob = cv2.dnn.blobFromImage(img, 1 / 255, (320, 320), swapRB=True, crop=False)
net.setInput(blob)
# Forward pass
layeroutputs = net.forward(ln)
# Initialize lists for detected bboxes, centroid values and
# probabilities (confidences)
bbox = []
centroids = []
confs = []
# print(layeroutputs)
for output in layeroutputs:
for det in output:
# To extract class index and associated probability
scores = det[5:]
classIdx = np.argmax(scores)
# print(classIdx)
conf = scores[classIdx]
# To ensure detected object is a person and that the
# probability crosses the confidence threshold value
if conf > confThreshold:
# Getting bbox coordinates
box = det[0:4] * np.array([wt, ht, wt, ht])
(center_X, center_Y, width, height) = box.astype('int')
x = int(center_X - (width / 2))
y = int(center_Y - (height / 2))
bbox.append([x, y, int(width), int(height)])
centroids.append((center_X, center_Y))
confs.append(float(conf))
# Applying non-maximum suppression to remove overlapping bboxes
indices = cv2.dnn.NMSBoxes(bbox, confs, confThreshold, nmsThreshold)
# Atleast one detection
if len(indices) > 0:
for i in indices.flatten():
(x, y) = (bbox[i][0], bbox[i][1])
(w, h) = (bbox[i][2], bbox[i][3])
result = (confs[i], (x, y, x + w, y + h), centroids[i])
results.append(result)
# Return results that contains person prediction probability,
# bbox coordinates and centroid of object
return results
#fourcc = cv2.VideoWriter_fourcc(*'MG')
out = cv2.VideoWriter('./static/output.mp4', cv2.VideoWriter_fourcc('M', 'P', '4', 'V'), 20, (640,480), isColor=True)
while True:
# Get image frames from video stream
success, img = cap.read()
# Resizing the img frames
img = cv2.resize(img, (640,480))
# Get layer names
layerNames = net.getLayerNames()
# print(layerNames)
# To get only the output layer names from the YOLO network
outputNames = [layerNames[i[0] - 1] for i in net.getUnconnectedOutLayers()]
# To detect only people
results = find_objects(img, net, outputNames, personIdx=classNames.index("person"))
# Warn if the minimum distance between objects is violated
warning = set()
# To ensure there are atleast 2 detections
if len(results) >= 2:
centroids = np.array([i[2] for i in results])
Dist = dist.cdist(centroids, centroids, metric="euclidean")
# Take upper triangular distance matrix and loop
for i in range(0, Dist.shape[0]):
for j in range(i + 1, Dist.shape[1]):
print(Dist[i, j])
if (Dist[i, j] < MinDist):
warning.add(i)
warning.add(j)
for (i, (prob, bbox, centroid)) in enumerate(results):
# Extracting bbox, centroids
(start_x, start_y, end_x, end_y) = bbox
(c_X, c_Y) = centroid
# Setting color to green if detected by default
color = (0, 255, 0)
# If distance is violated, send warning by changing color
# to red
if i in warning:
color = (0, 0, 255)
# Draw bboxes
cv2.rectangle(img, (start_x - 5, start_y - 5), (end_x + 5, end_y + 5), color, 2)
# Circle for centroid of the person
cv2.circle(img, (c_X, c_Y), 3, color, 1)
out.write(img)
cv2.imshow('Image', img)
k = cv2.waitKey(1) & 0xFF
if k == ord('q'):
break
cap.release()
out.release()
return render_template("complete.html")
if __name__=="__main__":
app.run(debug=True)