pose2sim/Pose2Sim/Utilities/trc_gaitevents.py

181 lines
6.3 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
##################################################
## GAIT EVENTS DETECTION ##
##################################################
Determine gait events according to Zeni et al. (2008).
Write them in gaitevents.txt (append results if file already exists).
t_HeelStrike = max(XHeel - Xsacrum)
t_ToeOff = min(XToe - XSacrum)
Reference:
“Two simple methods for determining gait events during treadmill and
overground walking using kinematic data.”
Gait & posture vol. 27,4 (2008): 710-4. doi:10.1016/j.gaitpost.2007.07.007
Usage:
Replace constants with the appropriate marker names.
If direction is negative, you need to include an equal sign in the argument,
eg -d=-Z or --gait_direction=-Z
from Pose2Sim.Utilities import trc_gaitevents; trc_gaitevents.trc_gaitevents_func(r'<input_trc_file>', '<gait_direction>')
OR python -m trc_gaitevents -i input_trc_file
OR python -m trc_gaitevents -i input_trc_file --gait_direction=-Z
'''
## CONSTANTS
R_SACRUM_MARKER = 'RHip'
R_HEEL_MARKER = 'RHeel'
R_TOE_MARKER = 'RBigToe'
L_SACRUM_MARKER = 'LHip'
L_HEEL_MARKER = 'LHeel'
L_TOE_MARKER = 'LBigToe'
## INIT
import os
import argparse
import pandas as pd
import numpy as np
from scipy import signal
## AUTHORSHIP INFORMATION
__author__ = "David Pagnon"
__copyright__ = "Copyright 2021, Pose2Sim"
__credits__ = ["David Pagnon"]
__license__ = "BSD 3-Clause License"
__version__ = "0.8.2"
__maintainer__ = "David Pagnon"
__email__ = "contact@david-pagnon.com"
__status__ = "Development"
## FUNCTIONS
def df_from_trc(trc_path):
'''
Retrieve header and data from trc path.
'''
# DataRate CameraRate NumFrames NumMarkers Units OrigDataRate OrigDataStartFrame OrigNumFrames
df_header = pd.read_csv(trc_path, sep="\t", skiprows=1, header=None, nrows=2, encoding="ISO-8859-1")
header = dict(zip(df_header.iloc[0].tolist(), df_header.iloc[1].tolist()))
# Label1_X Label1_Y Label1_Z Label2_X Label2_Y
df_lab = pd.read_csv(trc_path, sep="\t", skiprows=3, nrows=1)
labels = df_lab.columns.tolist()[2:-1:3]
labels_XYZ = np.array([[labels[i]+'_X', labels[i]+'_Y', labels[i]+'_Z'] for i in range(len(labels))], dtype='object').flatten()
labels_FTXYZ = np.concatenate((['Frame#','Time'], labels_XYZ))
data = pd.read_csv(trc_path, sep="\t", skiprows=5, index_col=False, header=None, names=labels_FTXYZ)
return header, data
def gait_events(trc_path, gait_direction):
'''
Determine gait events according to Zeni et al. (2008).
t_HellStrike = max(XHeel - Xsacrum)
t_ToeOff = min(XToe - XSacrum)
'''
# Read trc
header, data = df_from_trc(trc_path)
# In case of a sign in direction (eg -Z)
sign = ''
if any(x in gait_direction for x in ['-', '+']):
sign = gait_direction[0]
gait_direction = gait_direction[-1]
# Retrieve data of interest
XRSacrum = data['_'.join((R_SACRUM_MARKER, gait_direction))]
XRHeel = data['_'.join((R_HEEL_MARKER, gait_direction))]
XRToe = data['_'.join((R_TOE_MARKER, gait_direction))]
XLSacrum = data['_'.join((L_SACRUM_MARKER, gait_direction))]
XLHeel = data['_'.join((L_HEEL_MARKER, gait_direction))]
XLToe = data['_'.join((L_TOE_MARKER, gait_direction))]
# Prominence of the peaks
unit = header['Units']
peak_prominence = .1 if unit=='m' else 1 if unit=='dm' else 10 if unit=='cm' else 100 if unit=='mm' else np.inf
# Right and left heel strikes
frame_RHS = signal.find_peaks(eval(sign+'(XRHeel-XRSacrum)'),prominence=peak_prominence)[0]
t_RHS = data.loc[frame_RHS, 'Time'].tolist()
frame_LHS = signal.find_peaks(eval(sign+'(XLHeel-XLSacrum)'),prominence=peak_prominence)[0]
t_LHS = data.loc[frame_LHS, 'Time'].tolist()
# Right and left toe offs
frame_RTO = signal.find_peaks(eval(sign+'-(XRToe-XRSacrum)'),prominence=peak_prominence)[0]
t_RTO = data.loc[frame_RTO, 'Time'].tolist()
frame_LTO = signal.find_peaks(eval(sign+'-(XLToe-XLSacrum)'),prominence=peak_prominence)[0]
t_LTO = data.loc[frame_LTO, 'Time'].tolist()
return t_RHS, t_LHS, t_RTO, t_LTO
def trc_gaitevents_func(*args):
'''
Determine gait events according to Zeni et al. (2008).
Write them in gaitevents.txt (append results if file already exists).
t_HeelStrike = max(XHeel - Xsacrum)
t_ToeOff = min(XToe - XSacrum)
Reference:
“Two simple methods for determining gait events during treadmill and
overground walking using kinematic data.”
Gait & posture vol. 27,4 (2008): 710-4. doi:10.1016/j.gaitpost.2007.07.007
Usage:
Replace constants with the appropriate marker names in trc_gaitevents.py.
If direction is negative, you need to include an equal sign in the argument,
eg -d=-Z or --gait_direction=-Z
import trc_gaitevents; trc_gaitevents.trc_gaitevents_func(r'<input_trc_file>', '<gait_direction>')
OR trc_gaitevents -i input_trc_file --gait_direction Z
OR trc_gaitevents -i input_trc_file --gait_direction=-Z
'''
try:
trc_path = args[0].get('input_file') # invoked with argparse
gait_direction = args[0]['gait_direction']
except:
trc_path = args[0] # invoked as a function
try:
gait_direction = args[1]
except:
gait_direction = 'Z'
trc_dir = os.path.dirname(trc_path)
trc_name = os.path.basename(trc_path)
t_RHS, t_LHS, t_RTO, t_LTO = gait_events(trc_path, gait_direction)
with open(os.path.join(trc_dir, 'gaitevents.txt'), 'a') as gaitevents:
L = trc_name + '\n'
L += 'Right Heel strikes: ' + str(t_RHS) + '\n'
L += 'Left Heel strikes: ' + str(t_LHS) + '\n'
L += 'Right Toe off: ' + str(t_RTO) + '\n'
L += 'Left Toe off: ' + str(t_LTO) + '\n\n'
gaitevents.write(L)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input_file', required = True, help='trc input file')
parser.add_argument('-d', '--gait_direction', default = 'Z', required = False, help='direction of the gait. If negative, you need to include an equal sign in the argument, eg -d=-Z')
args = vars(parser.parse_args())
trc_gaitevents_func(args)