imumocap 0.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- imumocap-0.0.0/PKG-INFO +15 -0
- imumocap-0.0.0/README.md +1 -0
- imumocap-0.0.0/imumocap.egg-info/PKG-INFO +15 -0
- imumocap-0.0.0/imumocap.egg-info/SOURCES.txt +7 -0
- imumocap-0.0.0/imumocap.egg-info/dependency_links.txt +1 -0
- imumocap-0.0.0/imumocap.egg-info/top_level.txt +1 -0
- imumocap-0.0.0/imumocap.py +244 -0
- imumocap-0.0.0/setup.cfg +4 -0
- imumocap-0.0.0/setup.py +23 -0
imumocap-0.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: imumocap
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: IMU Mocap
|
|
5
|
+
Home-page: https://github.com/xioTechnologies/IMU-Mocap
|
|
6
|
+
Author: x-io Technologies Limited
|
|
7
|
+
Author-email: info@x-io.co.uk
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
See [github](https://github.com/xioTechnologies/IMU-Mocap) for documentation and examples.
|
imumocap-0.0.0/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# IMU-Mocap
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: imumocap
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: IMU Mocap
|
|
5
|
+
Home-page: https://github.com/xioTechnologies/IMU-Mocap
|
|
6
|
+
Author: x-io Technologies Limited
|
|
7
|
+
Author-email: info@x-io.co.uk
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
See [github](https://github.com/xioTechnologies/IMU-Mocap) for documentation and examples.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
imumocap
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import matplotlib.pyplot as pyplot
|
|
2
|
+
import numpy
|
|
3
|
+
from matplotlib import animation
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Link:
|
|
7
|
+
def __init__(self, name, length, connections=[]):
|
|
8
|
+
self.__name = name
|
|
9
|
+
self.__origin = Link.matrix() # origin in global frame
|
|
10
|
+
self.__joint = Link.matrix() # joint rotation relative to origin
|
|
11
|
+
self.__end = Link.matrix(x=length) # link end relative to origin
|
|
12
|
+
self.__imu = Link.matrix(x=length / 2) # IMU relative to origin
|
|
13
|
+
self.__connections = connections # [(matrix, link), ...] where matrix is the origin of the connecting link relative to the origin of this link
|
|
14
|
+
self.__update()
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def name(self):
|
|
18
|
+
return self.__name
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def joint(self):
|
|
22
|
+
return self.__joint
|
|
23
|
+
|
|
24
|
+
@joint.setter
|
|
25
|
+
def joint(self, value):
|
|
26
|
+
self.__joint[0:3, 0:3] = value[0:3, 0:3] # ignore translation
|
|
27
|
+
self.__update()
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def imu(self):
|
|
31
|
+
return self.__imu
|
|
32
|
+
|
|
33
|
+
@imu.setter
|
|
34
|
+
def imu(self, value):
|
|
35
|
+
self.__imu[0:3, 0:3] = value[0:3, 0:3] # ignore translation
|
|
36
|
+
self.__update()
|
|
37
|
+
|
|
38
|
+
def __update(self, origin=None):
|
|
39
|
+
if origin is not None:
|
|
40
|
+
self.__origin = origin
|
|
41
|
+
|
|
42
|
+
for link, matrix in self.__connections:
|
|
43
|
+
link.__update(self.__origin * self.joint * matrix)
|
|
44
|
+
|
|
45
|
+
def get_joint_global(self):
|
|
46
|
+
return self.__origin * self.__joint
|
|
47
|
+
|
|
48
|
+
def get_end_global(self):
|
|
49
|
+
return self.__origin * self.__joint * self.__end
|
|
50
|
+
|
|
51
|
+
def get_imu_global(self):
|
|
52
|
+
return self.__origin * self.__joint * self.__imu
|
|
53
|
+
|
|
54
|
+
def set_imu_global(self, imu_global):
|
|
55
|
+
self.imu = self.__joint.T * self.__origin.T * imu_global
|
|
56
|
+
|
|
57
|
+
def get_connections_global(self):
|
|
58
|
+
return [self.__origin * self.__joint * m for _, m in self.__connections]
|
|
59
|
+
|
|
60
|
+
def set_joint_from_imu_global(self, imu_global):
|
|
61
|
+
self.joint = self.__origin.T * imu_global * self.__imu.T
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def matrix(x=0, y=0, z=0, roll=0, pitch=0, yaw=0, quaternion=None):
|
|
65
|
+
if quaternion is not None:
|
|
66
|
+
qw = quaternion[0]
|
|
67
|
+
qx = quaternion[1]
|
|
68
|
+
qy = quaternion[2]
|
|
69
|
+
qz = quaternion[3]
|
|
70
|
+
|
|
71
|
+
return numpy.matrix([[2 * (qw * qw - 0.5 + qx * qx), 2 * (qx * qy - qw * qz), 2 * (qx * qz + qw * qy), x],
|
|
72
|
+
[2 * (qx * qy + qw * qz), 2 * (qw * qw - 0.5 + qy * qy), 2 * (qy * qz - qw * qx), y],
|
|
73
|
+
[2 * (qx * qz - qw * qy), 2 * (qy * qz + qw * qx), 2 * (qw * qw - 0.5 + qz * qz), z],
|
|
74
|
+
[0, 0, 0, 1]])
|
|
75
|
+
else:
|
|
76
|
+
sr = numpy.sin(numpy.radians(roll))
|
|
77
|
+
cr = numpy.cos(numpy.radians(roll))
|
|
78
|
+
|
|
79
|
+
sp = numpy.sin(numpy.radians(pitch))
|
|
80
|
+
cp = numpy.cos(numpy.radians(pitch))
|
|
81
|
+
|
|
82
|
+
sy = numpy.sin(numpy.radians(yaw))
|
|
83
|
+
cy = numpy.cos(numpy.radians(yaw))
|
|
84
|
+
|
|
85
|
+
return numpy.matrix([[cy * cp, cy * sp * sr - sy * cr, cy * sp * cr + sy * sr, x],
|
|
86
|
+
[sy * cp, sy * sp * sr + cy * cr, sy * sp * cr - cy * sr, y],
|
|
87
|
+
[-sp, cp * sr, cp * cr, z],
|
|
88
|
+
[0, 0, 0, 1]])
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def flatten(root):
|
|
92
|
+
links = [root]
|
|
93
|
+
|
|
94
|
+
for link, _ in root.__connections:
|
|
95
|
+
links = numpy.concatenate((links, Link.flatten(link)))
|
|
96
|
+
|
|
97
|
+
return links
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def plot(root, # root link
|
|
101
|
+
frames=None, # each frame is an nx4x4 array created by [l.joint.copy() for l in Link.flatten(root)]
|
|
102
|
+
fps=30, # animation frames per second
|
|
103
|
+
file_name="", # must be .gif
|
|
104
|
+
elev=None, # see mpl_toolkits.mplot3d.axes3d.Axes3D.view_init
|
|
105
|
+
azim=None, # see mpl_toolkits.mplot3d.axes3d.Axes3D.view_init
|
|
106
|
+
figsize=None, # see matplotlib.pyplot.figure
|
|
107
|
+
dpi=None): # see matplotlib.pyplot.figure
|
|
108
|
+
|
|
109
|
+
links = Link.flatten(root)
|
|
110
|
+
|
|
111
|
+
# Create figure
|
|
112
|
+
figure = pyplot.figure(figsize=figsize, dpi=dpi)
|
|
113
|
+
|
|
114
|
+
axis = pyplot.axes(projection="3d")
|
|
115
|
+
|
|
116
|
+
pyplot.subplots_adjust(top=0.95, bottom=0, left=0, right=1)
|
|
117
|
+
|
|
118
|
+
axis.set_xticklabels([])
|
|
119
|
+
axis.set_yticklabels([])
|
|
120
|
+
axis.set_zticklabels([])
|
|
121
|
+
|
|
122
|
+
# Create link quivers
|
|
123
|
+
link_quivers = axis.quiver([], [], [], [], [], [], color="tab:gray", zorder=-numpy.inf, label="Link")
|
|
124
|
+
|
|
125
|
+
# Create joint quivers and origins
|
|
126
|
+
joint_x_quivers = axis.quiver([], [], [], [], [], [], color="tab:red", label="X")
|
|
127
|
+
joint_y_quivers = axis.quiver([], [], [], [], [], [], color="tab:green", label="Y")
|
|
128
|
+
joint_z_quivers = axis.quiver([], [], [], [], [], [], color="tab:blue", label="Z")
|
|
129
|
+
|
|
130
|
+
joint_origins, = axis.plot([], [], [], "ko", markersize=4, zorder=numpy.inf, label="Joint")
|
|
131
|
+
|
|
132
|
+
# Create IMU quivers and origins
|
|
133
|
+
imu_standoff_quivers = axis.quiver([], [], [], [], [], [], color="tab:gray", zorder=-numpy.inf)
|
|
134
|
+
|
|
135
|
+
imu_x_quivers = axis.quiver([], [], [], [], [], [], color="tab:red")
|
|
136
|
+
imu_y_quivers = axis.quiver([], [], [], [], [], [], color="tab:green")
|
|
137
|
+
imu_z_quivers = axis.quiver([], [], [], [], [], [], color="tab:blue")
|
|
138
|
+
|
|
139
|
+
imu_origins, = axis.plot([], [], [], "ko", markersize=2, zorder=numpy.inf, label="IMU")
|
|
140
|
+
|
|
141
|
+
# Create labels text
|
|
142
|
+
labels = [axis.text(l.get_imu_global()[0, 3], l.get_imu_global()[1, 3], l.get_imu_global()[2, 3], l.name, zorder=numpy.inf) for l in links]
|
|
143
|
+
|
|
144
|
+
# Create frame index text
|
|
145
|
+
if frames is not None:
|
|
146
|
+
frame_index = pyplot.figtext(0.99, 0.01, "", horizontalalignment="right")
|
|
147
|
+
|
|
148
|
+
# Show legend
|
|
149
|
+
axis.legend(loc="upper left", frameon=0)
|
|
150
|
+
|
|
151
|
+
# Set view
|
|
152
|
+
axis.view_init(elev=elev, azim=azim)
|
|
153
|
+
|
|
154
|
+
# Update plot
|
|
155
|
+
def update(index):
|
|
156
|
+
|
|
157
|
+
# Set joint rotations
|
|
158
|
+
if index is not None:
|
|
159
|
+
for link, joint in zip(links, frames[index]):
|
|
160
|
+
link.joint = joint
|
|
161
|
+
|
|
162
|
+
# Set link quivers
|
|
163
|
+
origin_positions = numpy.array([l.get_joint_global()[:-1, 3].T.A1 for l in links])
|
|
164
|
+
end_positions = numpy.array([l.get_end_global()[:-1, 3].T.A1 for l in links])
|
|
165
|
+
|
|
166
|
+
link_quiver_segments = [[(o[0], o[1], o[2]), (e[0], e[1], e[2])] for o, e in zip(origin_positions, end_positions)]
|
|
167
|
+
|
|
168
|
+
for origin_position, end_position, connections in zip(origin_positions, end_positions, [l.get_connections_global() for l in links]):
|
|
169
|
+
for connection in connections:
|
|
170
|
+
link_quiver_segments.append([(origin_position[0], origin_position[1], origin_position[2]), (connection[0, 3], connection[1, 3], connection[2, 3])])
|
|
171
|
+
link_quiver_segments.append([(end_position[0], end_position[1], end_position[2]), (connection[0, 3], connection[1, 3], connection[2, 3])])
|
|
172
|
+
|
|
173
|
+
link_quivers.set_segments(link_quiver_segments)
|
|
174
|
+
|
|
175
|
+
# Set joint quivers and origins
|
|
176
|
+
joint_positions = numpy.array([l.get_joint_global()[:-1, 3].T.A1 for l in links])
|
|
177
|
+
joint_rotations = numpy.array([l.get_joint_global()[0:3, 0:3] for l in links])
|
|
178
|
+
|
|
179
|
+
JOINT_QUIVER_LENGTH = 0.4
|
|
180
|
+
joint_x_quiver_segments = [[(p[0], p[1], p[2]), (p[0] + r[0, 0], p[1] + r[1, 0], p[2] + r[2, 0])] for p, r in zip(joint_positions, JOINT_QUIVER_LENGTH * joint_rotations)]
|
|
181
|
+
joint_y_quiver_segments = [[(p[0], p[1], p[2]), (p[0] + r[0, 1], p[1] + r[1, 1], p[2] + r[2, 1])] for p, r in zip(joint_positions, JOINT_QUIVER_LENGTH * joint_rotations)]
|
|
182
|
+
joint_z_quiver_segments = [[(p[0], p[1], p[2]), (p[0] + r[0, 2], p[1] + r[1, 2], p[2] + r[2, 2])] for p, r in zip(joint_positions, JOINT_QUIVER_LENGTH * joint_rotations)]
|
|
183
|
+
|
|
184
|
+
joint_x_quivers.set_segments(joint_x_quiver_segments)
|
|
185
|
+
joint_y_quivers.set_segments(joint_y_quiver_segments)
|
|
186
|
+
joint_z_quivers.set_segments(joint_z_quiver_segments)
|
|
187
|
+
|
|
188
|
+
joint_origins.set_data(joint_positions[:, :2].T)
|
|
189
|
+
joint_origins.set_3d_properties(joint_positions[:, 2])
|
|
190
|
+
|
|
191
|
+
# Set IMU quivers and origins
|
|
192
|
+
IMU_STANDOFF = 0.2
|
|
193
|
+
imu_positions = numpy.array([l.get_imu_global()[:-1, 3].T.A1 for l in links])
|
|
194
|
+
imu_standoffs = numpy.array([(l.get_imu_global() * Link.matrix(z=IMU_STANDOFF))[:-1, 3].T.A1 for l in links])
|
|
195
|
+
imu_rotations = numpy.array([l.get_imu_global()[0:3, 0:3] for l in links])
|
|
196
|
+
|
|
197
|
+
imu_standoff_quivers.set_segments([[(p[0], p[1], p[2]), (s[0], s[1], s[2])] for p, s in zip(imu_positions, imu_standoffs)])
|
|
198
|
+
|
|
199
|
+
IMU_QUIVER_LENGTH = 0.2
|
|
200
|
+
imu_x_quiver_segments = [[(s[0], s[1], s[2]), (s[0] + r[0, 0], s[1] + r[1, 0], s[2] + r[2, 0])] for s, r in zip(imu_standoffs, IMU_QUIVER_LENGTH * imu_rotations)]
|
|
201
|
+
imu_y_quiver_segments = [[(s[0], s[1], s[2]), (s[0] + r[0, 1], s[1] + r[1, 1], s[2] + r[2, 1])] for s, r in zip(imu_standoffs, IMU_QUIVER_LENGTH * imu_rotations)]
|
|
202
|
+
imu_z_quiver_segments = [[(s[0], s[1], s[2]), (s[0] + r[0, 2], s[1] + r[1, 2], s[2] + r[2, 2])] for s, r in zip(imu_standoffs, IMU_QUIVER_LENGTH * imu_rotations)]
|
|
203
|
+
|
|
204
|
+
imu_x_quivers.set_segments(imu_x_quiver_segments)
|
|
205
|
+
imu_y_quivers.set_segments(imu_y_quiver_segments)
|
|
206
|
+
imu_z_quivers.set_segments(imu_z_quiver_segments)
|
|
207
|
+
|
|
208
|
+
imu_origins.set_data(imu_standoffs[:, :2].T)
|
|
209
|
+
imu_origins.set_3d_properties(imu_standoffs[:, 2])
|
|
210
|
+
|
|
211
|
+
# Set labels text positions
|
|
212
|
+
for label, imu in zip(labels, imu_standoffs):
|
|
213
|
+
label.set_position((imu[0], imu[1]))
|
|
214
|
+
label.set_3d_properties(z=imu[2], zdir=None)
|
|
215
|
+
|
|
216
|
+
# Set frame index text
|
|
217
|
+
if frames is not None:
|
|
218
|
+
frame_index.set_text("Frame " + str(index) + " of " + str(len(frames)))
|
|
219
|
+
|
|
220
|
+
# Set limits
|
|
221
|
+
all_xyz = numpy.concatenate((origin_positions, end_positions, joint_positions, imu_standoffs))
|
|
222
|
+
|
|
223
|
+
all_xyz = numpy.concatenate((all_xyz, [x[1] for x in joint_x_quiver_segments], [y[1] for y in joint_y_quiver_segments], [z[1] for z in joint_z_quiver_segments]))
|
|
224
|
+
|
|
225
|
+
all_xyz = numpy.concatenate((all_xyz, [x[1] for x in imu_x_quiver_segments], [y[1] for y in imu_y_quiver_segments], [z[1] for z in imu_z_quiver_segments]))
|
|
226
|
+
|
|
227
|
+
axis.set_xlim3d(numpy.min(all_xyz[:, 0]), numpy.max(all_xyz[:, 0]))
|
|
228
|
+
axis.set_ylim3d(numpy.min(all_xyz[:, 1]), numpy.max(all_xyz[:, 1]))
|
|
229
|
+
axis.set_zlim3d(numpy.min(all_xyz[:, 2]), numpy.max(all_xyz[:, 2]))
|
|
230
|
+
|
|
231
|
+
axis.set_box_aspect(numpy.ptp(all_xyz, axis=0))
|
|
232
|
+
|
|
233
|
+
# Static plot
|
|
234
|
+
if frames is None:
|
|
235
|
+
update(None)
|
|
236
|
+
return
|
|
237
|
+
|
|
238
|
+
# Animation
|
|
239
|
+
anim = animation.FuncAnimation(figure, update, frames=len(frames), interval=1000 / fps, repeat=False, blit=False)
|
|
240
|
+
|
|
241
|
+
if file_name:
|
|
242
|
+
anim.save(file_name, writer=animation.PillowWriter(fps), dpi="figure", progress_callback=lambda i, n: print(f"Saving frame {i + 1} of {n}"))
|
|
243
|
+
else:
|
|
244
|
+
pyplot.show() # play animation
|
imumocap-0.0.0/setup.cfg
ADDED
imumocap-0.0.0/setup.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
if len(sys.argv) == 1: # if this script was called without arguments
|
|
5
|
+
sys.argv.append("install")
|
|
6
|
+
sys.argv.append("--user")
|
|
7
|
+
|
|
8
|
+
github_url = "https://github.com/xioTechnologies/IMU-Mocap"
|
|
9
|
+
|
|
10
|
+
setup(name="imumocap",
|
|
11
|
+
version="0.0.0",
|
|
12
|
+
description="IMU Mocap",
|
|
13
|
+
long_description="See [github](" + github_url + ") for documentation and examples.",
|
|
14
|
+
long_description_content_type='text/markdown',
|
|
15
|
+
url=github_url,
|
|
16
|
+
author="x-io Technologies Limited",
|
|
17
|
+
author_email="info@x-io.co.uk",
|
|
18
|
+
license="MIT",
|
|
19
|
+
classifiers=["Programming Language :: Python :: 3.8",
|
|
20
|
+
"Programming Language :: Python :: 3.9",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11"], # versions shown by pyversions badge in README
|
|
23
|
+
py_modules=["imumocap"])
|