-
Notifications
You must be signed in to change notification settings - Fork 2
/
OpenPersonDetector.py
executable file
·300 lines (249 loc) · 11.8 KB
/
OpenPersonDetector.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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
'''
Person Detector and Leg Estimator based on OpenPose Project.
OpenPose Project Repo: https://github.com/CMU-Perceptual-Computing-Lab/openpose
'''
# NOTE:
# LD_LIBRARY_PATH should be set as [OPENPOSE_CAFFE_HOME]/build/lib/:[CUDA_HOME]/lib64:[OPENPOSE_HOME]build/lib:[Python3.5_Path]/dist-packages
import logging
from threading import RLock
import cv2
def initLibrary(preview, net_width, net_height):
'''
Loads Python wrapper on OpenPose (OpenPersonDetectorAPI)
:param preview: True to enable OP Preview
:param net_width: Detector net width
:param net_height: Detector net height
:return:
'''
if "person_detector_api" in globals():
logging.info("Library Init Already")
return
global person_detector_api
person_detector_api = None
import libOpenPersonDetectorAPI
person_detector_api = libOpenPersonDetectorAPI
person_detector_api.setup(preview, int(net_width), int(net_height))
# OP Mappings Index
coordinates_mapping = ["Nose", "Neck", "RShoulder", "RElbow", "RWrist", "LShoulder", "LElbow", "LWrist", "RHip",
"RKnee", "RAnkle", "LHip", "LKnee", "LAnkle", "REye", "LEye", "REar", "LEar", "Bkg"]
centralBodyKeywords = ["Nose", "Neck", "RShoulder", "LShoulder", "RHip", "RKnee", "RAnkle", "LHip", "LKnee", "LAnkle",
"REye", "LEye", "REar", "LEar", "Bkg"]
upperBodyKeywords = ["Neck", "RShoulder", "LShoulder", "RHip", "LHip", "Bkg"]
MAX_VALUE = 1000000
# Static Rules for detection of head orientation
head_direction_map = {}
# Nose, LEye, REye, LEar, REar
head_direction_map[(True, True, True, True, True)] = (0, 45)
head_direction_map[(True, False, False, True, True)] = (0, 45)
head_direction_map[(True, True, True, False, False)] = (0, 45)
head_direction_map[(True, True, True, True, False)] = (45, 45)
head_direction_map[(True, True, False, True, False)] = (90, 45)
head_direction_map[(True, True, False, True, True)] = (135, 45)
head_direction_map[(False, False, False, True, True)] = (180, 45)
head_direction_map[(True, False, True, True, True)] = (225, 45)
head_direction_map[(True, False, True, False, True)] = (270, 45)
head_direction_map[(True, True, True, False, True)] = (315, 45)
# Supplementary Rules
head_direction_map[(False, True, False, True, True)] = (135, 45)
head_direction_map[(True, False, False, False, True)] = (135, 45)
head_direction_map[(False, False, True, True, True)] = (225, 45)
head_direction_map[(True, False, False, True, False)] = (225, 45)
lock = RLock()
class OpenPersonDetector:
'''
Person Detector and Leg Estimator based on OpenPose Project.
OpenPose Project Repo: https://github.com/CMU-Perceptual-Computing-Lab/openpose
'''
def __init__(self, preview=True, net_width=656, net_height=368):
'''
Initialize OpenPose and Detector
:param preview:
:param net_width:
:param net_height:
'''
lock.acquire()
global person_detector_api
self.preview = preview
initLibrary(preview, net_width, net_height)
lock.release()
def _detectHeadDirection(self, human):
'''
Estimate head direction of human
:param human:
:return:
'''
lock.acquire()
key = ("Nose" in human.tracked_points.keys(), "LEye" in human.tracked_points.keys(),
"REye" in human.tracked_points.keys(), "LEar" in human.tracked_points.keys(),
"REar" in human.tracked_points.keys())
if key in head_direction_map.keys():
human.head_direction = head_direction_map[key][0]
human.head_direction_error = head_direction_map[key][1]
else:
# Failed to estimate
human.head_direction = None
human.head_direction_error = None
lock.release()
def detectPersons(self, colour_frame, gray_frame):
'''
Detect persons in frame
:param colour_frame: colour frame
:param gray_frame: gray frame (unused)
:return:
'''
lock.acquire()
global person_detector_api
# Obtain results
results = person_detector_api.detect(colour_frame)
# Obtain scale factors
results_height, results_width = person_detector_api.getOutputHeight(), person_detector_api.getOutputHeight()
frame_height, frame_width = colour_frame.shape[:2]
scale_factor = frame_height / results_height
# Preview output
if self.preview:
outputImage = person_detector_api.getOutputImage()
cv2.imshow("pose", outputImage)
person_detections = []
# For none detections
if results is None:
return []
# Process results
for i in range(len(results)):
# Add Detection
_person = results[i]
person_detection = PersonDetection()
person_detections.append(person_detection)
# Default bounds
minX = MAX_VALUE
maxX = -MAX_VALUE
minY = MAX_VALUE
maxY = -MAX_VALUE
minCentralX = MAX_VALUE
maxCentralX = -MAX_VALUE
minCentralY = MAX_VALUE
maxCentralY = -MAX_VALUE
minUpperX = MAX_VALUE
maxUpperX = -MAX_VALUE
minUpperY = MAX_VALUE
maxUpperY = -MAX_VALUE
# Update bounds
for j in range(len(_person)):
# Do scale correction
coordinate = _person[j]
#coordinate[0] = coordinate[0] * scale_factor
#coordinate[1] = coordinate[1] * scale_factor
if coordinate[2] > 0: # In presence of point
person_detection.tracked_points[coordinates_mapping[j]] = coordinate[:]
minX = min(coordinate[0], minX)
minY = min(coordinate[1], minY)
maxX = max(coordinate[0], maxX)
maxY = max(coordinate[1], maxY)
# Update bounds
if coordinates_mapping[j] in centralBodyKeywords:
minCentralX = min(coordinate[0], minCentralX)
minCentralY = min(coordinate[1], minCentralY)
maxCentralX = max(coordinate[0], maxCentralX)
maxCentralY = max(coordinate[1], maxCentralY)
if coordinates_mapping[j] in upperBodyKeywords:
minUpperX = min(coordinate[0], minUpperX)
minUpperY = min(coordinate[1], minUpperY)
maxUpperX = max(coordinate[0], maxUpperX)
maxUpperY = max(coordinate[1], maxUpperY)
def findAverage(names):
'''
Finds average of coordinates with corresponding names
:param names:
:return:
'''
total = None
count = 0
for name in names:
if name in person_detection.tracked_points.keys():
if total is None:
total = [0, 0]
total[0] += person_detection.tracked_points[name][0]
total[1] += person_detection.tracked_points[name][1]
count += 1
if total is not None:
total[0] = total[0] / count
total[1] = total[1] / count
return total
# Update result fields
person_detection.person_bound = (minX, minY, maxX, maxY)
person_detection.central_bound = (minCentralX, minCentralY, maxCentralX, maxCentralY)
person_detection.central_point = ((minCentralX + maxCentralX) / 2, (minCentralY + maxCentralY) / 2)
person_detection.upper_body_bound = (minUpperX, minUpperY, maxUpperX, maxUpperY)
legCount = 0 # Number of visible legs
legSet = False # Is leg position known?
legY = 0 # Y coordinate of leg
legX = 0
# Obtain leg point
if "LAnkle" in person_detection.tracked_points.keys():
legY = max(legY, person_detection.tracked_points["LAnkle"][1])
if legY == person_detection.tracked_points["LAnkle"][1]:
legX = person_detection.tracked_points["LAnkle"][0]
legSet = True
legCount += 1
if "RAnkle" in person_detection.tracked_points.keys():
legY = max(legY, person_detection.tracked_points["RAnkle"][1])
if legY == person_detection.tracked_points["RAnkle"][1]:
legX = person_detection.tracked_points["RAnkle"][0]
legSet = True
legCount += 1
# find other points of interest
hip = findAverage(["RHip", "LHip"])
neck = findAverage(["Neck"])
ankle = findAverage(["RAnkle", "LAnkle"])
knee = findAverage(["RKnee", "LKnee"])
elbow = findAverage(["RElbow","LElbow"])
if elbow is not None:
person_detection.elbow_point = elbow
if hip is not None:
person_detection.hip_point = hip
if hip is not None and neck is not None:
# Estimate leg Y using hip,neck,leg ratio
person_detection.estimated_leg_point = (
person_detection.central_point[0], neck[1] + 2.3 * (hip[1] - neck[1]))
# person_detection.estimated_leg_point = (person_detection.central_point[0],
# person_detection.upper_body_bound[1] +
# (person_detection.upper_body_bound[3] - person_detection.upper_body_bound[1])* 2)
else:
# Estimate leg y using bounds
logging.info("Poor Estimate of Leg Point")
person_detection.estimated_leg_point = (person_detection.central_point[0],
person_detection.central_bound[1] +
(person_detection.central_bound[3] -
person_detection.central_bound[1]) * 1)
if not legSet:
# If leg point is not known, use estimate
legX = person_detection.central_point[0]
legY = person_detection.estimated_leg_point[1]
person_detection.leg_point = (legX, legY)
person_detection.leg_count = legCount
# Calculate neck_hip_ankle ratio
if hip is not None and neck is not None and ankle is not None:
person_detection.neck_hip_ankle_ratio = (ankle[1] - neck[1]) / (hip[1] - neck[1])
if hip is not None and neck is not None and knee is not None:
person_detection.neck_hip_knee_ratio = (knee[1] - neck[1]) / (hip[1] - neck[1])
self._detectHeadDirection(person_detection)
lock.release()
return person_detections
class PersonDetection:
'''
Detection of a person
'''
def __init__(self):
self.tracked_points = {} # Points detected by OP
self.person_bound = None # Boundary of person
self.central_bound = None # Boundary of central body of person (no hands and feet for X coordinate)
self.upper_body_bound = None # Boundary of upper body of person
self.central_point = None # Central point of person
self.leg_point = None # Average Feet point of person
self.leg_count = None # Number of detected feet
self.estimated_leg_point = None # Estimated feet point of person
self.neck_hip_ankle_ratio = None
self.neck_hip_knee_ratio = None
self.head_direction = None
self.head_direction_error = None
self.hip_point = None
self.elbow_point = None