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.
@@ -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
+ # 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,7 @@
1
+ README.md
2
+ imumocap.py
3
+ setup.py
4
+ imumocap.egg-info/PKG-INFO
5
+ imumocap.egg-info/SOURCES.txt
6
+ imumocap.egg-info/dependency_links.txt
7
+ imumocap.egg-info/top_level.txt
@@ -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
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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"])