Spaces:
Running
Running
updated instruction and buttons and progression bar
Browse files- app.py +93 -126
- example_mot_complete_kinematics.mot +0 -0
- example_mot_missing_knee_kinematics.mot +0 -0
- example_opensim_model.osim +0 -0
app.py
CHANGED
|
@@ -538,8 +538,8 @@ class GaussianDiffusion(nn.Module):
|
|
| 538 |
|
| 539 |
|
| 540 |
class FillingBase:
|
| 541 |
-
def fill_param(self, windows, diffusion_model_for_filling):
|
| 542 |
-
return self.filling(windows, diffusion_model_for_filling, self.update_kinematics_and_masks_for_masking_column)
|
| 543 |
|
| 544 |
@staticmethod
|
| 545 |
def update_kinematics_and_masks_for_masking_column(windows, samples, i_win, masks):
|
|
@@ -565,9 +565,10 @@ class FillingBase:
|
|
| 565 |
|
| 566 |
class DiffusionFilling(FillingBase):
|
| 567 |
@staticmethod
|
| 568 |
-
def filling(windows, diffusion_model_for_filling, windows_update_func):
|
| 569 |
windows = copy.deepcopy(windows)
|
| 570 |
-
|
|
|
|
| 571 |
state_true = torch.stack([win.pose for win in windows[i_win:i_win+opt.batch_size_inference]])
|
| 572 |
masks = torch.stack([win.mask for win in windows[i_win:i_win+opt.batch_size_inference]])
|
| 573 |
cond = torch.ones([6])
|
|
@@ -579,6 +580,11 @@ class DiffusionFilling(FillingBase):
|
|
| 579 |
# samples[:, :, opt.kinetic_diffusion_col_loc] = state_true[:, :, opt.kinetic_diffusion_col_loc]
|
| 580 |
|
| 581 |
windows = windows_update_func(windows, samples, i_win, masks)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 582 |
return windows
|
| 583 |
|
| 584 |
def __str__(self):
|
|
@@ -1238,16 +1244,16 @@ def convertDfToGRFMot(df, out_path, dt, time_column):
|
|
| 1238 |
|
| 1239 |
plate_num = 2
|
| 1240 |
|
| 1241 |
-
for i in range(1, 1 + plate_num):
|
| 1242 |
-
out_file.write('\t' + f'
|
| 1243 |
-
out_file.write('\t' + f'
|
| 1244 |
-
out_file.write('\t' + f'
|
| 1245 |
-
out_file.write('\t' + f'
|
| 1246 |
-
out_file.write('\t' + f'
|
| 1247 |
-
out_file.write('\t' + f'
|
| 1248 |
-
out_file.write('\t' + f'
|
| 1249 |
-
out_file.write('\t' + f'
|
| 1250 |
-
out_file.write('\t' + f'
|
| 1251 |
|
| 1252 |
out_file.write('\n')
|
| 1253 |
for i in range(numFrames):
|
|
@@ -2626,78 +2632,6 @@ class TrialData:
|
|
| 2626 |
|
| 2627 |
""" ============================ End dataset.py ============================ """
|
| 2628 |
|
| 2629 |
-
|
| 2630 |
-
# def usr_inputs():
|
| 2631 |
-
# opt = parse_opt()
|
| 2632 |
-
|
| 2633 |
-
# # # [DEBUG]
|
| 2634 |
-
# # opt.height_m = 1.84
|
| 2635 |
-
# # opt.weight_kg = 71.4
|
| 2636 |
-
# # opt.treadmill_speed = 1.15
|
| 2637 |
-
# # opt.subject_osim_model = opt.subject_data_path + '/Scaled_generic_no_arm.osim'
|
| 2638 |
-
|
| 2639 |
-
# input("Upload .mot files and a .osim file to Colab via \n \
|
| 2640 |
-
# 1) click the folder button on the left side of the window \n \
|
| 2641 |
-
# 2) upload .mot files to the default folder (/content/) by clicking \"Upload to session storage\" button and \n \
|
| 2642 |
-
# 3) upload .osim file to the default folder (/content/) by clicking \"Upload to session storage\" button. \n \
|
| 2643 |
-
# Please confirm completion and then entering anything ")
|
| 2644 |
-
|
| 2645 |
-
# file_paths = []
|
| 2646 |
-
# for file in os.listdir(opt.subject_data_path):
|
| 2647 |
-
# file_path = os.path.join(opt.subject_data_path, file)
|
| 2648 |
-
# if file.endswith(".mot") and '_pred___' not in file:
|
| 2649 |
-
# file_paths.append(file_path)
|
| 2650 |
-
# if len(file_paths) == 0:
|
| 2651 |
-
# raise RuntimeError(f'No .mot file found. Upload the .mot file to Colab')
|
| 2652 |
-
# opt.file_paths = file_paths
|
| 2653 |
-
|
| 2654 |
-
# osim_paths = []
|
| 2655 |
-
# for file in os.listdir(opt.subject_data_path):
|
| 2656 |
-
# file_path = os.path.join(opt.subject_data_path, file)
|
| 2657 |
-
# if file.endswith(".osim"):
|
| 2658 |
-
# osim_paths.append(file_path)
|
| 2659 |
-
# if len(osim_paths) > 1:
|
| 2660 |
-
# print(f'Multiple .osim files found.')
|
| 2661 |
-
# [print(f'{i}: {file_path}') for i, file_path in enumerate(osim_paths)]
|
| 2662 |
-
# i_file = int(input(f'Choose the .osim file entering its index (between 0 and {len(osim_paths)-1}): '))
|
| 2663 |
-
# opt.subject_osim_model = osim_paths[i_file]
|
| 2664 |
-
# elif len(osim_paths) == 0:
|
| 2665 |
-
# raise RuntimeError(f'No .osim file found. Upload the .osim file to Colab')
|
| 2666 |
-
# else:
|
| 2667 |
-
# opt.subject_osim_model = osim_paths[0]
|
| 2668 |
-
# print()
|
| 2669 |
-
|
| 2670 |
-
# while True:
|
| 2671 |
-
# try:
|
| 2672 |
-
# opt.height_m = float(input("Enter the subject's height in meter: "))
|
| 2673 |
-
# if opt.height_m > 2.5 or opt.height_m < 1:
|
| 2674 |
-
# raise ValueError()
|
| 2675 |
-
# print()
|
| 2676 |
-
# break
|
| 2677 |
-
# except ValueError:
|
| 2678 |
-
# print("Invalid input. Please enter a floating-point number between 1.0 and 2.5.")
|
| 2679 |
-
# while True:
|
| 2680 |
-
# try:
|
| 2681 |
-
# opt.weight_kg = float(input("Enter the subject's weight in Kg: "))
|
| 2682 |
-
# if opt.weight_kg > 200 or opt.weight_kg < 30:
|
| 2683 |
-
# raise ValueError()
|
| 2684 |
-
# print()
|
| 2685 |
-
# break
|
| 2686 |
-
# except ValueError:
|
| 2687 |
-
# print("Invalid input. Please enter a floating-point number between 30 and 200.")
|
| 2688 |
-
# while True:
|
| 2689 |
-
# try:
|
| 2690 |
-
# opt.treadmill_speed = float(input("Enter treadmill speed in m/s (enter 0 for overground gait): "))
|
| 2691 |
-
# if opt.treadmill_speed > 10 or opt.treadmill_speed < 0:
|
| 2692 |
-
# raise ValueError()
|
| 2693 |
-
# print()
|
| 2694 |
-
# break
|
| 2695 |
-
# except ValueError:
|
| 2696 |
-
# print("Invalid input. Please enter a floating-point number between 0 and 10.")
|
| 2697 |
-
|
| 2698 |
-
# return opt
|
| 2699 |
-
|
| 2700 |
-
|
| 2701 |
def predict_grf_and_missing_kinematics():
|
| 2702 |
refinement_model = BaselineModel(opt, TransformerEncoderArchitecture)
|
| 2703 |
dataset = MotionDataset(opt, normalizer=refinement_model.normalizer)
|
|
@@ -2756,7 +2690,7 @@ import io
|
|
| 2756 |
import shutil
|
| 2757 |
|
| 2758 |
opt = parse_opt()
|
| 2759 |
-
def gradio_predict(mot_file, osim_file, height_m, weight_kg, treadmill_speed):
|
| 2760 |
"""Gradio interface function for GRF prediction."""
|
| 2761 |
if mot_file is None:
|
| 2762 |
return "Please upload a .mot file"
|
|
@@ -2790,7 +2724,7 @@ def gradio_predict(mot_file, osim_file, height_m, weight_kg, treadmill_speed):
|
|
| 2790 |
opt.subject_osim_model = osim_path
|
| 2791 |
|
| 2792 |
# Run prediction with updated opt
|
| 2793 |
-
output_files = predict_grf_and_missing_kinematics_with_opt()
|
| 2794 |
|
| 2795 |
if output_files:
|
| 2796 |
return "Prediction completed! Download files below.", output_files[0], output_files[1] if len(output_files) > 1 else None
|
|
@@ -2799,7 +2733,7 @@ def gradio_predict(mot_file, osim_file, height_m, weight_kg, treadmill_speed):
|
|
| 2799 |
except Exception as e:
|
| 2800 |
return f"Error during prediction: {str(e)}", None, None
|
| 2801 |
|
| 2802 |
-
def predict_grf_and_missing_kinematics_with_opt():
|
| 2803 |
"""Modified prediction function that accepts opt as parameter."""
|
| 2804 |
refinement_model = BaselineModel(opt, TransformerEncoderArchitecture)
|
| 2805 |
dataset = MotionDataset(opt, normalizer=refinement_model.normalizer)
|
|
@@ -2816,7 +2750,7 @@ def predict_grf_and_missing_kinematics_with_opt():
|
|
| 2816 |
f'\nGenerating missing kinematics for {dataset.file_names[i_trial]}')
|
| 2817 |
if diffusion_model_for_filling is None:
|
| 2818 |
diffusion_model_for_filling, _ = load_diffusion_model(opt)
|
| 2819 |
-
windows_reconstructed = filling_method.fill_param(windows, diffusion_model_for_filling)
|
| 2820 |
else:
|
| 2821 |
windows_reconstructed = windows
|
| 2822 |
|
|
@@ -2932,43 +2866,74 @@ with gr.Blocks(css="""
|
|
| 2932 |
}
|
| 2933 |
#plotting_panel {min-height: 700px !important;}
|
| 2934 |
""") as demo:
|
| 2935 |
-
gr.Markdown(
|
| 2936 |
-
|
| 2937 |
-
|
| 2938 |
-
|
| 2939 |
-
|
| 2940 |
-
|
| 2941 |
-
|
| 2942 |
-
|
| 2943 |
-
|
| 2944 |
-
|
| 2945 |
-
|
| 2946 |
-
|
| 2947 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2948 |
|
| 2949 |
gr.Markdown("### Input Data and Parameters")
|
| 2950 |
with gr.Row():
|
| 2951 |
mot_in = gr.File(label="Upload .mot file", file_types=[".mot"])
|
| 2952 |
osim_in = gr.File(label="Upload .osim file", file_types=[".osim"])
|
| 2953 |
with gr.Row():
|
| 2954 |
-
height_in = gr.Number(label="Height (meters)", value=1.
|
| 2955 |
-
weight_in = gr.Number(label="Weight (kg)", value=
|
| 2956 |
-
speed_in = gr.Number(label="Treadmill speed (m/s, 0 for overground)", value=
|
| 2957 |
|
| 2958 |
submit_btn = gr.Button("Submit")
|
| 2959 |
|
| 2960 |
gr.Markdown("### Results")
|
| 2961 |
with gr.Row():
|
| 2962 |
status_out = gr.Textbox(label="Status")
|
|
|
|
|
|
|
| 2963 |
with gr.Row():
|
| 2964 |
-
grf_file_out = gr.
|
| 2965 |
-
kin_file_out = gr.
|
| 2966 |
|
| 2967 |
# Plotting panel
|
| 2968 |
with gr.Column(elem_id="plotting_panel"):
|
| 2969 |
gr.Markdown("""
|
| 2970 |
### Visualization
|
| 2971 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2972 |
""")
|
| 2973 |
with gr.Row():
|
| 2974 |
file_select = gr.Radio(choices=["GRF Results", "Missing Kinematics"], value="GRF Results", label="Select output file")
|
|
@@ -2977,33 +2942,35 @@ with gr.Blocks(css="""
|
|
| 2977 |
plot_out = gr.Plot(label="Time series plot")
|
| 2978 |
|
| 2979 |
# Wire interactions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2980 |
submit_btn.click(
|
| 2981 |
-
fn=
|
| 2982 |
-
inputs=[mot_in, osim_in, height_in, weight_in, speed_in],
|
| 2983 |
-
outputs=[status_out, grf_file_out, kin_file_out]
|
| 2984 |
)
|
| 2985 |
|
| 2986 |
file_select.change(
|
| 2987 |
fn=list_mot_columns,
|
| 2988 |
-
inputs=[file_select,
|
| 2989 |
-
outputs=[column_select]
|
| 2990 |
-
)
|
| 2991 |
-
|
| 2992 |
-
grf_file_out.change(
|
| 2993 |
-
fn=list_mot_columns,
|
| 2994 |
-
inputs=[file_select, grf_file_out, kin_file_out],
|
| 2995 |
-
outputs=[column_select]
|
| 2996 |
-
)
|
| 2997 |
-
|
| 2998 |
-
kin_file_out.change(
|
| 2999 |
-
fn=list_mot_columns,
|
| 3000 |
-
inputs=[file_select, grf_file_out, kin_file_out],
|
| 3001 |
outputs=[column_select]
|
| 3002 |
)
|
| 3003 |
|
| 3004 |
plot_btn.click(
|
| 3005 |
fn=plot_mot_signal,
|
| 3006 |
-
inputs=[file_select, column_select,
|
| 3007 |
outputs=[plot_out]
|
| 3008 |
)
|
| 3009 |
|
|
|
|
| 538 |
|
| 539 |
|
| 540 |
class FillingBase:
|
| 541 |
+
def fill_param(self, windows, diffusion_model_for_filling, progress_callback=None):
|
| 542 |
+
return self.filling(windows, diffusion_model_for_filling, self.update_kinematics_and_masks_for_masking_column, progress_callback=progress_callback)
|
| 543 |
|
| 544 |
@staticmethod
|
| 545 |
def update_kinematics_and_masks_for_masking_column(windows, samples, i_win, masks):
|
|
|
|
| 565 |
|
| 566 |
class DiffusionFilling(FillingBase):
|
| 567 |
@staticmethod
|
| 568 |
+
def filling(windows, diffusion_model_for_filling, windows_update_func, progress_callback=None):
|
| 569 |
windows = copy.deepcopy(windows)
|
| 570 |
+
total_iterations = len(range(0, len(windows), opt.batch_size_inference))
|
| 571 |
+
for iteration_idx, i_win in enumerate(range(0, len(windows), opt.batch_size_inference)):
|
| 572 |
state_true = torch.stack([win.pose for win in windows[i_win:i_win+opt.batch_size_inference]])
|
| 573 |
masks = torch.stack([win.mask for win in windows[i_win:i_win+opt.batch_size_inference]])
|
| 574 |
cond = torch.ones([6])
|
|
|
|
| 580 |
# samples[:, :, opt.kinetic_diffusion_col_loc] = state_true[:, :, opt.kinetic_diffusion_col_loc]
|
| 581 |
|
| 582 |
windows = windows_update_func(windows, samples, i_win, masks)
|
| 583 |
+
|
| 584 |
+
# Report progress: 10% for first iteration, 90% for last iteration
|
| 585 |
+
if progress_callback:
|
| 586 |
+
progress = 0.1 + 0.8 * (iteration_idx + 1) / total_iterations
|
| 587 |
+
progress_callback(progress)
|
| 588 |
return windows
|
| 589 |
|
| 590 |
def __str__(self):
|
|
|
|
| 1244 |
|
| 1245 |
plate_num = 2
|
| 1246 |
|
| 1247 |
+
for i, side in zip(range(1, 1 + plate_num), ['r', 'l']):
|
| 1248 |
+
out_file.write('\t' + f'force_{side}_vx')
|
| 1249 |
+
out_file.write('\t' + f'force_{side}_vy')
|
| 1250 |
+
out_file.write('\t' + f'force_{side}_vz')
|
| 1251 |
+
out_file.write('\t' + f'force_{side}_px')
|
| 1252 |
+
out_file.write('\t' + f'force_{side}_py')
|
| 1253 |
+
out_file.write('\t' + f'force_{side}_pz')
|
| 1254 |
+
out_file.write('\t' + f'torque_{side}_x')
|
| 1255 |
+
out_file.write('\t' + f'torque_{side}_y')
|
| 1256 |
+
out_file.write('\t' + f'torque_{side}_z')
|
| 1257 |
|
| 1258 |
out_file.write('\n')
|
| 1259 |
for i in range(numFrames):
|
|
|
|
| 2632 |
|
| 2633 |
""" ============================ End dataset.py ============================ """
|
| 2634 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2635 |
def predict_grf_and_missing_kinematics():
|
| 2636 |
refinement_model = BaselineModel(opt, TransformerEncoderArchitecture)
|
| 2637 |
dataset = MotionDataset(opt, normalizer=refinement_model.normalizer)
|
|
|
|
| 2690 |
import shutil
|
| 2691 |
|
| 2692 |
opt = parse_opt()
|
| 2693 |
+
def gradio_predict(mot_file, osim_file, height_m, weight_kg, treadmill_speed, progress_callback=None):
|
| 2694 |
"""Gradio interface function for GRF prediction."""
|
| 2695 |
if mot_file is None:
|
| 2696 |
return "Please upload a .mot file"
|
|
|
|
| 2724 |
opt.subject_osim_model = osim_path
|
| 2725 |
|
| 2726 |
# Run prediction with updated opt
|
| 2727 |
+
output_files = predict_grf_and_missing_kinematics_with_opt(progress_callback=progress_callback)
|
| 2728 |
|
| 2729 |
if output_files:
|
| 2730 |
return "Prediction completed! Download files below.", output_files[0], output_files[1] if len(output_files) > 1 else None
|
|
|
|
| 2733 |
except Exception as e:
|
| 2734 |
return f"Error during prediction: {str(e)}", None, None
|
| 2735 |
|
| 2736 |
+
def predict_grf_and_missing_kinematics_with_opt(progress_callback=None):
|
| 2737 |
"""Modified prediction function that accepts opt as parameter."""
|
| 2738 |
refinement_model = BaselineModel(opt, TransformerEncoderArchitecture)
|
| 2739 |
dataset = MotionDataset(opt, normalizer=refinement_model.normalizer)
|
|
|
|
| 2750 |
f'\nGenerating missing kinematics for {dataset.file_names[i_trial]}')
|
| 2751 |
if diffusion_model_for_filling is None:
|
| 2752 |
diffusion_model_for_filling, _ = load_diffusion_model(opt)
|
| 2753 |
+
windows_reconstructed = filling_method.fill_param(windows, diffusion_model_for_filling, progress_callback=progress_callback)
|
| 2754 |
else:
|
| 2755 |
windows_reconstructed = windows
|
| 2756 |
|
|
|
|
| 2866 |
}
|
| 2867 |
#plotting_panel {min-height: 700px !important;}
|
| 2868 |
""") as demo:
|
| 2869 |
+
gr.Markdown(
|
| 2870 |
+
"""
|
| 2871 |
+
# GaitDynamics - Ground Reaction Force and Kinematics Prediction
|
| 2872 |
+
### General instructions
|
| 2873 |
+
This code is for ground reaction force and missing kinematics prediction using flexible combinations of OpenSim joint angles. The joint angles should meet the following criteria:
|
| 2874 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">1. Use OpenSim <a href="https://simtk.org/projects/full_body">Rajagopal Model without Arms</a>.</div>
|
| 2875 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">2. Resample to 100 Hz if you have a different sampling rate.</div>
|
| 2876 |
+
|
| 2877 |
+
To use this code:
|
| 2878 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">1. Upload OpenSim model (.osim) and kinematics (.mot) file. If kinematics are provided for all coordinates, the model will only predict ground reaction forces. If kinematics are missing, the model will also predict missing kinematics.</div>
|
| 2879 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">2. Enter the height and weight of the participant, and the treadmill speed (if applicable).</div>
|
| 2880 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">3. Click the "Submit " button.</div>
|
| 2881 |
+
|
| 2882 |
+
### Processing example data
|
| 2883 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">1. Download the example files:</div>
|
| 2884 |
+
"""
|
| 2885 |
+
)
|
| 2886 |
+
with gr.Column():
|
| 2887 |
+
with gr.Row():
|
| 2888 |
+
gr.DownloadButton("a. OpenSim model file (.osim)", value="example_opensim_model.osim", size="sm", scale=1)
|
| 2889 |
+
gr.DownloadButton("b. complete kinematics file with all coordinates (.mot)", value="example_mot_complete_kinematics.mot", size="sm", scale=1)
|
| 2890 |
+
gr.DownloadButton("c. incomplete kinematics file with missing knee coordinate kinematics (.mot)", value="example_mot_missing_knee_kinematics.mot", size="sm", scale=1)
|
| 2891 |
+
gr.Markdown(
|
| 2892 |
+
"""
|
| 2893 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">2. Upload data for either of the two example .mot files.</div>
|
| 2894 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">a. Predict ground reaction forces with a complete kinematics file by uploading the model file (.osim) and complete kinematics file (.mot).</div>
|
| 2895 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">b. Predict ground reaction forces with an incomplete kinematics file by uploading the model file (.osim) and the incomplete kinematics file (.mot).</div>
|
| 2896 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">3. Update the following input parameters.</div>
|
| 2897 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">a. Height = 1.84 m</div>
|
| 2898 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">b. Weight = 70 kg</div>
|
| 2899 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">c. Treadmill speed = 1.15 m/s</div>
|
| 2900 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">4. Click "Submit".</div>
|
| 2901 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">a. The example with complete kinematics should take a few seconds to complete.</div>
|
| 2902 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">b. The example with incomplete kinematics should take a few minutes to complete.</div>
|
| 2903 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">5. Plot the data, starting with GRF Results and choosing columns (e.g., force_r_vy).</div>
|
| 2904 |
+
"""
|
| 2905 |
+
)
|
| 2906 |
|
| 2907 |
gr.Markdown("### Input Data and Parameters")
|
| 2908 |
with gr.Row():
|
| 2909 |
mot_in = gr.File(label="Upload .mot file", file_types=[".mot"])
|
| 2910 |
osim_in = gr.File(label="Upload .osim file", file_types=[".osim"])
|
| 2911 |
with gr.Row():
|
| 2912 |
+
height_in = gr.Number(label="Height (meters)", value=1.83, minimum=1.0, maximum=2.5, step=0.01)
|
| 2913 |
+
weight_in = gr.Number(label="Weight (kg)", value=71.4, minimum=30, maximum=200, step=0.1)
|
| 2914 |
+
speed_in = gr.Number(label="Treadmill speed (m/s, 0 for overground)", value=1.15, minimum=0, maximum=10, step=0.01)
|
| 2915 |
|
| 2916 |
submit_btn = gr.Button("Submit")
|
| 2917 |
|
| 2918 |
gr.Markdown("### Results")
|
| 2919 |
with gr.Row():
|
| 2920 |
status_out = gr.Textbox(label="Status")
|
| 2921 |
+
grf_path = gr.State(None)
|
| 2922 |
+
kin_path = gr.State(None)
|
| 2923 |
with gr.Row():
|
| 2924 |
+
grf_file_out = gr.DownloadButton("Download Ground Reaction Force Results", size="sm", scale=1, visible=False)
|
| 2925 |
+
kin_file_out = gr.DownloadButton("Download Missing Kinematics (0 for overground)", size="sm", scale=1, visible=False)
|
| 2926 |
|
| 2927 |
# Plotting panel
|
| 2928 |
with gr.Column(elem_id="plotting_panel"):
|
| 2929 |
gr.Markdown("""
|
| 2930 |
### Visualization
|
| 2931 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">Ground reaction force (GRF) results are available for all inputs. Missing kinematics results are only available if incomplete kinematics were used as inputs.</div>
|
| 2932 |
+
<div style="padding-left: 2em; text-indent: -1.0em;">GRF column names follow these conventions:</div>
|
| 2933 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">• Starts with force_l or force_r: indicates the left or right foot, respectively</div>
|
| 2934 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">• Ends in _vx, _vy, _vz: indicates the magnitude value of the force in the x, y, and z directions, respectively.</div>
|
| 2935 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">• Ends in _vx, _vy, _vz: indicates the point location of the center of pressure in the x, y, and z directions, respectively.</div>
|
| 2936 |
+
<div style="padding-left: 3.5em; text-indent: -1.0em;">• x is the anterior direction, y is the vertical direction, and z is the direction pointing to the right (medial or lateral direction depending on the leg).</div>
|
| 2937 |
""")
|
| 2938 |
with gr.Row():
|
| 2939 |
file_select = gr.Radio(choices=["GRF Results", "Missing Kinematics"], value="GRF Results", label="Select output file")
|
|
|
|
| 2942 |
plot_out = gr.Plot(label="Time series plot")
|
| 2943 |
|
| 2944 |
# Wire interactions
|
| 2945 |
+
def enhanced_predict(mot_in, osim_in, height_in, weight_in, speed_in, current_select, current_grf, current_kin, progress=gr.Progress()):
|
| 2946 |
+
progress(0.0, desc="Starting...")
|
| 2947 |
+
|
| 2948 |
+
def progress_callback(pct):
|
| 2949 |
+
progress(pct, desc=f"Processing diffusion model... {int(pct*100)}%")
|
| 2950 |
+
|
| 2951 |
+
status, new_grf, new_kin = gradio_predict(mot_in, osim_in, height_in, weight_in, speed_in, progress_callback=progress_callback)
|
| 2952 |
+
progress(1.0, desc="Complete!")
|
| 2953 |
+
|
| 2954 |
+
columns = list_mot_columns(current_select, new_grf, new_kin)
|
| 2955 |
+
grf_visible = new_grf is not None
|
| 2956 |
+
kin_visible = new_kin is not None
|
| 2957 |
+
return status, new_grf, new_kin, gr.update(value=new_grf, visible=grf_visible), gr.update(value=new_kin, visible=kin_visible), columns
|
| 2958 |
+
|
| 2959 |
submit_btn.click(
|
| 2960 |
+
fn=enhanced_predict,
|
| 2961 |
+
inputs=[mot_in, osim_in, height_in, weight_in, speed_in, file_select, grf_path, kin_path],
|
| 2962 |
+
outputs=[status_out, grf_path, kin_path, grf_file_out, kin_file_out, column_select]
|
| 2963 |
)
|
| 2964 |
|
| 2965 |
file_select.change(
|
| 2966 |
fn=list_mot_columns,
|
| 2967 |
+
inputs=[file_select, grf_path, kin_path],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2968 |
outputs=[column_select]
|
| 2969 |
)
|
| 2970 |
|
| 2971 |
plot_btn.click(
|
| 2972 |
fn=plot_mot_signal,
|
| 2973 |
+
inputs=[file_select, column_select, grf_path, kin_path],
|
| 2974 |
outputs=[plot_out]
|
| 2975 |
)
|
| 2976 |
|
example_mot_complete_kinematics.mot
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
example_mot_missing_knee_kinematics.mot
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
example_opensim_model.osim
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|