Skip to content

Commit 974cfce

Browse files
committed
Fix pose tracking routine
1 parent e920f40 commit 974cfce

File tree

7 files changed

+182
-859
lines changed

7 files changed

+182
-859
lines changed

pose_tracking/cubemos_api.py

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
#!/usr/bin/env python3
2-
1+
#!/usr/bin/env python
2+
# Title :loader.py
3+
# Author :Venkatraman Narayanan, Bala Murali Manoghar, Vishnu Shashank Dorbala, Aniket Bera, Dinesh Manocha
4+
# Copyright :"Copyright 2020, Proxemo project"
5+
# Version :1.0
6+
# License :"MIT"
7+
# Maintainer :Venkatraman Narayanan, Bala Murali Manoghar
8+
9+
# ==============================================================================
310
import argparse
411
import os
512
import platform
@@ -28,6 +35,14 @@
2835

2936

3037
def default_log_dir():
38+
"""Get default cubemos log dir.
39+
40+
Raises:
41+
Exception: Works only on Windows/Linux
42+
43+
Returns:
44+
[str]: Default log directory
45+
"""
3146
if platform.system() == "Windows":
3247
return os.path.join(os.environ["LOCALAPPDATA"], "Cubemos", "SkeletonTracking", "logs")
3348
elif platform.system() == "Linux":
@@ -37,6 +52,14 @@ def default_log_dir():
3752

3853

3954
def default_license_dir():
55+
"""Get license file location.
56+
57+
Raises:
58+
Exception: Works only on Windows/Linux
59+
60+
Returns:
61+
[str]: License file directory
62+
"""
4063
if platform.system() == "Windows":
4164
return os.path.join(os.environ["LOCALAPPDATA"], "Cubemos", "SkeletonTracking", "license")
4265
elif platform.system() == "Linux":
@@ -46,6 +69,7 @@ def default_license_dir():
4669

4770

4871
def check_license_and_variables_exist():
72+
"""Check license file."""
4973
license_path = os.path.join(default_license_dir(), "cubemos_license.json")
5074
if not os.path.isfile(license_path):
5175
raise Exception(
@@ -57,13 +81,24 @@ def check_license_and_variables_exist():
5781
raise Exception(
5882
"The environment Variable \"CUBEMOS_SKEL_SDK\" is not set. "
5983
"Please check the troubleshooting section in the Getting "
60-
"Started Guide to resolve this issue."
84+
"Started Guide to resolve this issue."
6185
)
6286

6387

6488
def get_valid_limbs(keypoint_ids, skeleton, confidence_threshold):
89+
"""Extract limbs based on confidence
90+
91+
Args:
92+
keypoint_ids (list(tuple)): Joint ID pair (limbs)
93+
skeleton (obj): Skeleton joint points
94+
confidence_threshold (float): Threshold
95+
96+
Returns:
97+
[lsit]: valid limbs (connections)
98+
"""
6599
limbs = [
66-
(tuple(map(int, skeleton.joints[i])), tuple(map(int, skeleton.joints[v])))
100+
(tuple(map(int, skeleton.joints[i])),
101+
tuple(map(int, skeleton.joints[v])))
67102
for (i, v) in keypoint_ids
68103
if skeleton.confidences[i] >= confidence_threshold
69104
and skeleton.confidences[v] >= confidence_threshold
@@ -77,34 +112,17 @@ def get_valid_limbs(keypoint_ids, skeleton, confidence_threshold):
77112

78113

79114
def render_result(skeletons, img, confidence_threshold):
115+
"""Generate skeleton overlay on image (inplace).
116+
117+
Args:
118+
skeletons (dict): skeleton joint co-ordinates
119+
img (np.array): source image
120+
confidence_threshold (float): Threshold
121+
"""
80122
skeleton_color = (100, 254, 213)
81123
for index, skeleton in enumerate(skeletons):
82124
limbs = get_valid_limbs(keypoint_ids, skeleton, confidence_threshold)
83125
for limb in limbs:
84126
cv2.line(
85127
img, limb[0], limb[1], skeleton_color, thickness=2, lineType=cv2.LINE_AA
86-
)
87-
88-
# parser = argparse.ArgumentParser(description="Perform keypoing estimation on an image")
89-
# parser.add_argument(
90-
# "-c",
91-
# "--confidence_threshold",
92-
# type=float,
93-
# default=0.5,
94-
# help="Minimum confidence (0-1) of displayed joints",
95-
# )
96-
# parser.add_argument(
97-
# "-v",
98-
# "--verbose",
99-
# action="store_true",
100-
# help="Increase output verbosity by enabling backend logging",
101-
# )
102-
103-
# parser.add_argument(
104-
# "-o",
105-
# "--output_image",
106-
# type=str,
107-
# help="filename of the output image",
108-
# )
109-
110-
# parser.add_argument("image", metavar="I", type=str, help="filename of the input image")
128+
)

pose_tracking/cubemos_wrapper.py

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
#!/usr/bin/env python3
2-
3-
# cubemos init
1+
#!/usr/bin/env python
2+
# Title :loader.py
3+
# Author :Venkatraman Narayanan, Bala Murali Manoghar, Vishnu Shashank Dorbala, Aniket Bera, Dinesh Manocha
4+
# Copyright :"Copyright 2020, Proxemo project"
5+
# Version :1.0
6+
# License :"MIT"
7+
# Maintainer :Venkatraman Narayanan, Bala Murali Manoghar
8+
9+
# ==============================================================================
410
import os
511
import numpy as np
612
import cv2
@@ -37,7 +43,15 @@
3743

3844

3945
class Cubemos_Tacker():
46+
"""Cubemos skeletal tracker class."""
47+
4048
def __init__(self, intrinsics, verbose=False):
49+
"""Constructor.
50+
51+
Args:
52+
intrinsics (np.array): Camera instrinsics matrix
53+
verbose (bool, optional): Verbose log. Defaults to False.
54+
"""
4155
self.verbose = verbose
4256
self.intrinsics = intrinsics
4357
self.confidence_threshold = 0.3
@@ -54,6 +68,7 @@ def __init__(self, intrinsics, verbose=False):
5468
self.init_cubemos_api()
5569

5670
def init_skel_track(self):
71+
"""Skeleton tracking initializer."""
5772
check_license_and_variables_exist()
5873
# Get the path of the native libraries and ressource files
5974
self.sdk_path = os.environ["CUBEMOS_SKEL_SDK"]
@@ -64,6 +79,7 @@ def init_skel_track(self):
6479
default_log_dir())
6580

6681
def init_cubemos_api(self):
82+
"""Setup cubemos API."""
6783
# initialize the api with a valid license key in default_license_dir()
6884
self.api = Api(default_license_dir())
6985
model_path = os.path.join(self.sdk_path,
@@ -74,6 +90,12 @@ def init_cubemos_api(self):
7490
self.api.load_model(CM_TargetComputeDevice.CM_CPU, model_path)
7591

7692
def track_skeletons(self, image, depth_image):
93+
"""Track skeleton from image frame to deptg frame.
94+
95+
Args:
96+
image (np.array): RGB image
97+
depth_image (np.array): depth image
98+
"""
7799
# perform inference
78100
self.skeletons = self.api.estimate_keypoints(
79101
image, self.network_height)
@@ -88,6 +110,11 @@ def track_skeletons(self, image, depth_image):
88110
self.skel2D_to_skel3D(depth_image)
89111

90112
def render_skeletons(self, image):
113+
"""Overlay detected skeleton on image.
114+
115+
Args:
116+
image (np.array): RGB image
117+
"""
91118
render_result(self.skeletons, image, self.confidence_threshold)
92119
for skel_num, joints in enumerate(self.skel3d_np):
93120
for joint_ndx, pt_3D in enumerate(joints[[0, -1]]):
@@ -115,6 +142,15 @@ def render_skeletons(self, image):
115142
2, (255, 0, 255), -1)
116143

117144
def map_2D_3D(self, pixel, depth):
145+
"""Match camera frame to depth frame
146+
147+
Args:
148+
pixel (np.array): pixel co-ordinates
149+
depth (np.array): depth co-ordinates
150+
151+
Returns:
152+
[np.array]: 3D point co-ordinates
153+
"""
118154
x = (pixel[0] - self.intrinsics.ppx) / self.intrinsics.fx
119155
y = (pixel[1] - self.intrinsics.ppy) / self.intrinsics.fy
120156

@@ -139,6 +175,11 @@ def map_2D_3D(self, pixel, depth):
139175
return (X, Y, Z)
140176

141177
def skel2D_to_skel3D(self, depth_image):
178+
"""Convert a 2D skeleton in Camera frame to 3D co-ordinates.
179+
180+
Args:
181+
depth_image (np.array): depth image
182+
"""
142183
self.skel_ids = []
143184
self.skel3d_np = []
144185
self.roots_2d = []

pose_tracking/human_tracking_3D.py

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
#!/usr/bin/env python3
2-
1+
#!/usr/bin/env python
2+
# Title :loader.py
3+
# Author :Venkatraman Narayanan, Bala Murali Manoghar, Vishnu Shashank Dorbala, Aniket Bera, Dinesh Manocha
4+
# Copyright :"Copyright 2020, Proxemo project"
5+
# Version :1.0
6+
# License :"MIT"
7+
# Maintainer :Venkatraman Narayanan, Bala Murali Manoghar
8+
9+
# ==============================================================================
310
import cv2
411
import numpy as np
512

@@ -8,18 +15,39 @@
815

916

1017
class Skel_Temporal():
18+
"""Skeleton gait generator class."""
19+
1120
def __init__(self, skel_id, do_not_ignore_false_limbs=True):
21+
"""Constructor
22+
23+
Args:
24+
skel_id (int): Skeleton ID
25+
do_not_ignore_false_limbs (bool, optional): Ignore false limbs?. Defaults to True.
26+
"""
1227
self.id = skel_id
1328
self.skel_temporal = []
1429
self.do_not_ignore_false_limbs = do_not_ignore_false_limbs
1530

1631
def add(self, skel_ti):
32+
"""Add skeleton to tracking.
33+
34+
Args:
35+
skel_ti (np.array): skeleton co-ordinates
36+
"""
1737
if not np.any(skel_ti == -1) or self.ignore_false_limbs:
1838
if len(self.skel_temporal) > 75:
1939
self.skel_temporal.pop(0)
2040
self.skel_temporal.append(skel_ti)
2141

2242
def __eq__(self, other):
43+
"""Skeleton compare
44+
45+
Args:
46+
other (obj): Skeleton Object
47+
48+
Returns:
49+
[bool]: Same/different skeleton
50+
"""
2351
try:
2452
if self.id == other.id:
2553
return True
@@ -32,6 +60,11 @@ def __eq__(self, other):
3260
return False
3361

3462
def get_embedding(self):
63+
"""Convert Temporal gait cycle to Image sequence.
64+
65+
Returns:
66+
[np.array]: Gait cycle embedded as image
67+
"""
3568
skel_temporal_np = np.array(self.skel_temporal)
3669
# make root as (0, 0, 0)
3770
# even if number of frames is less than 75 it will be resized to 244*244
@@ -42,12 +75,25 @@ def get_embedding(self):
4275

4376

4477
class Skel_Tracker():
78+
"""Skeleton Tracking Class."""
79+
4580
def __init__(self, do_not_ignore_false_limbs=True):
81+
"""Constructor.
82+
83+
Args:
84+
do_not_ignore_false_limbs (bool, optional): Ignore false limbs?. Defaults to True.
85+
"""
4686
self.skel_tracks = []
4787
self.img_embeddings = []
4888
self.do_not_ignore_false_limbs = do_not_ignore_false_limbs
4989

5090
def update(self, skel_nps, skel_ids):
91+
"""Add skeleton pose to sequence.
92+
93+
Args:
94+
skel_nps (np.array): Skeleton co-ordinates
95+
skel_ids (list): Skeleton IDs
96+
"""
5197
# add skeleton corresponding to id
5298
for skel_np, skel_id in zip(skel_nps, skel_ids):
5399
try:
@@ -75,6 +121,11 @@ def update(self, skel_nps, skel_ids):
75121
self.skel_tracks.pop(value - ndx)
76122

77123
def get_embedding(self):
124+
"""Generate image embedding for entire gait sequence.
125+
126+
Returns:
127+
[list]: image embeddings, skeleton IDs
128+
"""
78129
self.img_embeddings = []
79130
ids = []
80131
for skel_track in self.skel_tracks:
@@ -84,6 +135,7 @@ def get_embedding(self):
84135
return self.img_embeddings, ids
85136

86137
def display_embedding(self):
138+
"""View image embeddings."""
87139
imgs = self.img_embeddings[0] # np.empty((244,244,3))
88140
print(self.img_embeddings.shape)
89141
for img in self.img_embeddings[1:]:
@@ -94,7 +146,15 @@ def display_embedding(self):
94146

95147

96148
class Track_Human_Pose():
149+
"""Main gait tracking loop."""
150+
97151
def __init__(self, display=True, verbose=True):
152+
"""Constructor.
153+
154+
Args:
155+
display (bool, optional): Show skeleton detections?. Defaults to True.
156+
verbose (bool, optional): Generate verbose log?. Defaults to True.
157+
"""
98158
self.verbose = verbose
99159
self.display = display
100160

@@ -104,6 +164,7 @@ def __init__(self, display=True, verbose=True):
104164
self.skel_tracker = Skel_Tracker()
105165

106166
def get_pose(self):
167+
"""Get human skeletons."""
107168
# capture
108169
self.camera.capture()
109170
# get skeletons
@@ -121,10 +182,12 @@ def get_pose(self):
121182
cv2.imshow('RealSense', images)
122183

123184
def track_pose(self):
185+
"""Track skeleton gaits."""
124186
self.skel_tracker.update(self.cubemos.skel3d_np,
125187
self.cubemos.skel_ids)
126188

127189
def cleanup(self):
190+
"""Cleanup workspace setup."""
128191
self.camera.cleanup()
129192

130193

0 commit comments

Comments
 (0)