c3d-parser 0.3.4__tar.gz → 0.4.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.
- {c3d_parser-0.3.4/src/c3d_parser.egg-info → c3d_parser-0.4.0}/PKG-INFO +4 -2
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/requirements.txt +3 -1
- c3d_parser-0.4.0/src/c3d_parser/__init__.py +2 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/core/c3d_parser.py +17 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/core/osim.py +9 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/main_window.py +29 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/ui/ui_main_window.py +6 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0/src/c3d_parser.egg-info}/PKG-INFO +4 -2
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser.egg-info/requires.txt +3 -1
- c3d_parser-0.3.4/src/c3d_parser/__init__.py +0 -2
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/LICENSE +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/README.md +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/pyproject.toml +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/setup.cfg +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/application.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/core/c3d_patch.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/core/osim_resources/external_loads_template.xml +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/core/osim_resources/ik_task_set.xml +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/core/utils.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/settings/general.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/settings/logging.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/settings/marker_maps/AUC.json +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/settings/marker_maps/FMC.json +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/settings/marker_maps/MH.json +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/settings/marker_maps/QCMAS.json +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/settings/marker_maps/RBWH.json +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/settings/marker_maps/RCH.json +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/settings/marker_maps/Sydney.json +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/splash_rc.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/splashscreen.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/dialogs/about_dialog.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/dialogs/marker_set_dialog.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/dialogs/marker_set_import_dialog.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/dialogs/options_dialog.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/ui/resources_rc.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/ui/ui_marker_set_dialog.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/ui/ui_marker_set_import_dialog.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/ui/ui_options_dialog.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/utils.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/widgets.py +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser.egg-info/SOURCES.txt +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser.egg-info/dependency_links.txt +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser.egg-info/entry_points.txt +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser.egg-info/top_level.txt +0 -0
- {c3d_parser-0.3.4 → c3d_parser-0.4.0}/tests/test_parser.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: c3d-parser
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: C3D parser for gait data harmonisation.
|
|
5
5
|
Author-email: Timothy Salemink <tim.nicolas@outlook.com>, Sally Jack <sallyjaack@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -12,10 +12,12 @@ Requires-Dist: numpy==1.26.4
|
|
|
12
12
|
Requires-Dist: pandas
|
|
13
13
|
Requires-Dist: c3d==0.5.2
|
|
14
14
|
Requires-Dist: trc-data-reader
|
|
15
|
-
Requires-Dist: opensim-model-creator>=0.
|
|
15
|
+
Requires-Dist: opensim-model-creator>=0.2.0
|
|
16
16
|
Requires-Dist: PySide6
|
|
17
17
|
Requires-Dist: matplotlib
|
|
18
18
|
Requires-Dist: mplcursors
|
|
19
|
+
Requires-Dist: pyvistaqt
|
|
20
|
+
Requires-Dist: ll-visualiser
|
|
19
21
|
Dynamic: license-file
|
|
20
22
|
|
|
21
23
|
# C3D-parser
|
|
@@ -329,6 +329,8 @@ def harmonise_markers(frame_data, lab, required_markers):
|
|
|
329
329
|
if None in frame_data.columns:
|
|
330
330
|
frame_data.drop(columns=frame_data.columns[frame_data.columns.isna()], inplace=True)
|
|
331
331
|
|
|
332
|
+
# TODO: This error window does not indicate which trial has the issue.
|
|
333
|
+
# Update this.
|
|
332
334
|
# Ensure required markers are present.
|
|
333
335
|
available = set(frame_data.columns)
|
|
334
336
|
for item in required_markers:
|
|
@@ -382,8 +384,10 @@ def trim_frames(frame_data):
|
|
|
382
384
|
if not drop_frames.empty:
|
|
383
385
|
frame_data.drop(drop_frames, inplace=True)
|
|
384
386
|
|
|
387
|
+
# TODO: If we convert this to a dictionary we can keep the markers that are missing and check if they are required.
|
|
385
388
|
remaining_frames = [frame for frame in incomplete_frames.keys() if trim_start <= frame <= trim_end]
|
|
386
389
|
if remaining_frames:
|
|
390
|
+
# TODO: We should raise a ParserError (skip this trial) if the missing markers are required...?
|
|
387
391
|
logger.warn(f"Frames {remaining_frames} are incomplete.")
|
|
388
392
|
|
|
389
393
|
return trim_start, trim_end
|
|
@@ -597,6 +601,14 @@ def extract_data(file_path, start_frame, end_frame):
|
|
|
597
601
|
return analog_data, reader.analog_rate, trimmed_events, plate_count, corners
|
|
598
602
|
|
|
599
603
|
|
|
604
|
+
# TODO: Georgio asked if we could maybe provide a way to approximate some of these values (from markers),
|
|
605
|
+
# if they haven't measured them.
|
|
606
|
+
# ...
|
|
607
|
+
# Thor suggests taking this value from the model.
|
|
608
|
+
# ...
|
|
609
|
+
# Discuss this with Elyse to see if she's Ok with this/
|
|
610
|
+
# If she can get the other labs to agree/
|
|
611
|
+
# See how each lab measures this.
|
|
600
612
|
def extract_static_data(file_path):
|
|
601
613
|
with open(file_path, 'rb') as handle:
|
|
602
614
|
reader = c3d.Reader(handle)
|
|
@@ -1410,6 +1422,11 @@ def add_medial_knee_markers(frame_data, left_knee_width, right_knee_width, marke
|
|
|
1410
1422
|
def create_osim_model(static_trc, dynamic_trc, static_marker_data, marker_diameter, static_data,
|
|
1411
1423
|
output_directory, optimise_knee_axis, progress_tracker):
|
|
1412
1424
|
|
|
1425
|
+
# TODO: Lazy import this here.
|
|
1426
|
+
# Reduce startup time.
|
|
1427
|
+
# We might be able to "warm up" this import in the background before we get here as well.
|
|
1428
|
+
# from opensim_model_creator.Create_Model import create_model
|
|
1429
|
+
|
|
1413
1430
|
static_marker_data = static_marker_data.drop("Time").to_dict()
|
|
1414
1431
|
rotation_matrix = np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])
|
|
1415
1432
|
static_marker_data = {k: np.dot(rotation_matrix, v) for k, v in static_marker_data.items()}
|
|
@@ -18,6 +18,11 @@ def perform_ik(osim_file, trc_file, output_file):
|
|
|
18
18
|
ik_tool.setModel(model)
|
|
19
19
|
ik_tool.setMarkerDataFileName(trc_file)
|
|
20
20
|
ik_tool.set_IKTaskSet(osim.IKTaskSet(IK_TASK_SET))
|
|
21
|
+
|
|
22
|
+
# TODO: Fix Teresa's OpenSim issue.
|
|
23
|
+
# ik_tool.setResultsDir(r"C:\Users\MyUser\AppData\Local\MyApp\results")
|
|
24
|
+
# ik_tool.setResultsDir(output_directory)
|
|
25
|
+
|
|
21
26
|
ik_tool.setOutputMotionFileName(output_file)
|
|
22
27
|
ik_tool.set_report_errors(False)
|
|
23
28
|
ik_tool.run()
|
|
@@ -34,9 +39,13 @@ def perform_id(osim_file, ik_file, grf_file, output_file):
|
|
|
34
39
|
id_tool = osim.InverseDynamicsTool()
|
|
35
40
|
id_tool.setModel(model)
|
|
36
41
|
id_tool.setCoordinatesFileName(ik_file)
|
|
42
|
+
|
|
43
|
+
# TODO: Temporarily disable.
|
|
37
44
|
id_tool.setExternalLoadsFileName(external_loads_file)
|
|
45
|
+
|
|
38
46
|
id_tool.setResultsDir(output_directory)
|
|
39
47
|
id_tool.setOutputGenForceFileName(output_file_name)
|
|
48
|
+
# TODO: We shouldn't need this since the data (IK results) are already filtered.
|
|
40
49
|
id_tool.setLowpassCutoffFrequency(6)
|
|
41
50
|
id_tool.setStartTime(time_values[0])
|
|
42
51
|
id_tool.setEndTime(time_values[-1])
|
|
@@ -12,6 +12,8 @@ from PySide6.QtWidgets import (QApplication, QMainWindow, QMenu, QFileDialog, QL
|
|
|
12
12
|
QWidget, QVBoxLayout, QHBoxLayout)
|
|
13
13
|
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
|
|
14
14
|
from matplotlib.figure import Figure
|
|
15
|
+
from pyvistaqt import QtInteractor
|
|
16
|
+
from ll_visualiser.visualiser import visualise_model
|
|
15
17
|
|
|
16
18
|
from c3d_parser.core.c3d_parser import (parse_session, extract_static_data, extract_marker_names, is_dynamic,
|
|
17
19
|
CancelException, write_normalised_kinematics, write_normalised_kinetics, write_spatiotemporal_data)
|
|
@@ -53,6 +55,13 @@ class ProgressTracker(QObject):
|
|
|
53
55
|
progress = Signal(str, str)
|
|
54
56
|
|
|
55
57
|
|
|
58
|
+
# TODO: Add the deidentified name to the column in the file details.
|
|
59
|
+
# Instead of just "Dynamic", "Dynamic_1" or whatever.
|
|
60
|
+
# ...
|
|
61
|
+
# Nah just create local mapping file directly in input directory.
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# TODO: CGM2 event detector on GitHub...?
|
|
56
65
|
class MainWindow(QMainWindow):
|
|
57
66
|
|
|
58
67
|
def __init__(self):
|
|
@@ -86,6 +95,7 @@ class MainWindow(QMainWindow):
|
|
|
86
95
|
self._load_settings()
|
|
87
96
|
self._setup_progress_bar()
|
|
88
97
|
self._validate_directory()
|
|
98
|
+
self._setup_visualiser()
|
|
89
99
|
|
|
90
100
|
self._grf_curves = GaitCurves(self._grf_canvas)
|
|
91
101
|
self._kinematic_curves = GaitCurves(self._kinematic_canvas)
|
|
@@ -96,6 +106,14 @@ class MainWindow(QMainWindow):
|
|
|
96
106
|
self._progress_value = 0
|
|
97
107
|
self._ui.progressBar.setVisible(False)
|
|
98
108
|
|
|
109
|
+
def _setup_visualiser(self):
|
|
110
|
+
self._plotter = QtInteractor(self._ui.tabVisualiser)
|
|
111
|
+
self._plotter.set_background('#2b2b2b')
|
|
112
|
+
self._ui.tabVisualiser.layout().addWidget(self._plotter.interactor)
|
|
113
|
+
|
|
114
|
+
def _clear_visualiser(self):
|
|
115
|
+
self._plotter.clear_actors()
|
|
116
|
+
|
|
99
117
|
def _clear_progress_bar(self):
|
|
100
118
|
self._progress_text = ""
|
|
101
119
|
self._ui.labelProgress.setText("")
|
|
@@ -303,6 +321,7 @@ class MainWindow(QMainWindow):
|
|
|
303
321
|
self._reset_kinematic_plots()
|
|
304
322
|
self._reset_kinetic_plots()
|
|
305
323
|
self._clear_spatiotemporal_data()
|
|
324
|
+
self._clear_visualiser()
|
|
306
325
|
|
|
307
326
|
def _validate_directory(self):
|
|
308
327
|
input_directory = self._ui.lineEditInputDirectory.text()
|
|
@@ -514,6 +533,7 @@ class MainWindow(QMainWindow):
|
|
|
514
533
|
self._visualise_kinematic_data(self._kinematic_data)
|
|
515
534
|
self._visualise_kinetic_data(self._kinetic_data)
|
|
516
535
|
self._visualise_spatiotemporal_data()
|
|
536
|
+
self._visualise_model()
|
|
517
537
|
|
|
518
538
|
self._show_selected_trials()
|
|
519
539
|
self._progress_tracker.progress.emit("Process completed successfully", "green")
|
|
@@ -543,6 +563,15 @@ class MainWindow(QMainWindow):
|
|
|
543
563
|
self._progress_value = min(self._progress_value + 20, 100)
|
|
544
564
|
self._ui.progressBar.setValue(self._progress_value)
|
|
545
565
|
|
|
566
|
+
def _visualise_model(self):
|
|
567
|
+
model_directory = os.path.join(self._output_directory, "Models", "Meshes")
|
|
568
|
+
left_original_landmark_file = os.path.join(model_directory, 'original_lms_left.txt')
|
|
569
|
+
right_original_landmark_file = os.path.join(model_directory, 'original_lms_right.txt')
|
|
570
|
+
left_predicted_landmark_file = os.path.join(model_directory, 'predicted_lms_left.txt')
|
|
571
|
+
right_predicted_landmark_file = os.path.join(model_directory, 'predicted_lms_right.txt')
|
|
572
|
+
visualise_model(self._plotter, model_directory, left_original_landmark_file, right_original_landmark_file,
|
|
573
|
+
left_predicted_landmark_file, right_predicted_landmark_file)
|
|
574
|
+
|
|
546
575
|
@handle_runtime_error
|
|
547
576
|
def _harmonise_data(self):
|
|
548
577
|
selected = self._get_selected_trials()
|
|
@@ -522,6 +522,11 @@ class Ui_MainWindow(object):
|
|
|
522
522
|
self.verticalLayout_8.addWidget(self.scrollArea)
|
|
523
523
|
|
|
524
524
|
self.tabWidget.addTab(self.tabSpatiotemporal, "")
|
|
525
|
+
self.tabVisualiser = QWidget()
|
|
526
|
+
self.tabVisualiser.setObjectName(u"tabVisualiser")
|
|
527
|
+
self.verticalLayout_13 = QVBoxLayout(self.tabVisualiser)
|
|
528
|
+
self.verticalLayout_13.setObjectName(u"verticalLayout_13")
|
|
529
|
+
self.tabWidget.addTab(self.tabVisualiser, "")
|
|
525
530
|
|
|
526
531
|
self.verticalLayout_3.addWidget(self.tabWidget)
|
|
527
532
|
|
|
@@ -638,6 +643,7 @@ class Ui_MainWindow(object):
|
|
|
638
643
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabKinetic), QCoreApplication.translate("MainWindow", u"Kinetic", None))
|
|
639
644
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabGRF), QCoreApplication.translate("MainWindow", u"GRF", None))
|
|
640
645
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabSpatiotemporal), QCoreApplication.translate("MainWindow", u"Spatio-temporal", None))
|
|
646
|
+
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabVisualiser), QCoreApplication.translate("MainWindow", u"Visualiser", None))
|
|
641
647
|
self.labelProgress.setText("")
|
|
642
648
|
self.menuFile.setTitle(QCoreApplication.translate("MainWindow", u"File", None))
|
|
643
649
|
self.menuView.setTitle(QCoreApplication.translate("MainWindow", u"View", None))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: c3d-parser
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: C3D parser for gait data harmonisation.
|
|
5
5
|
Author-email: Timothy Salemink <tim.nicolas@outlook.com>, Sally Jack <sallyjaack@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -12,10 +12,12 @@ Requires-Dist: numpy==1.26.4
|
|
|
12
12
|
Requires-Dist: pandas
|
|
13
13
|
Requires-Dist: c3d==0.5.2
|
|
14
14
|
Requires-Dist: trc-data-reader
|
|
15
|
-
Requires-Dist: opensim-model-creator>=0.
|
|
15
|
+
Requires-Dist: opensim-model-creator>=0.2.0
|
|
16
16
|
Requires-Dist: PySide6
|
|
17
17
|
Requires-Dist: matplotlib
|
|
18
18
|
Requires-Dist: mplcursors
|
|
19
|
+
Requires-Dist: pyvistaqt
|
|
20
|
+
Requires-Dist: ll-visualiser
|
|
19
21
|
Dynamic: license-file
|
|
20
22
|
|
|
21
23
|
# C3D-parser
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/core/osim_resources/external_loads_template.xml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{c3d_parser-0.3.4 → c3d_parser-0.4.0}/src/c3d_parser/view/dialogs/marker_set_import_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|