2024-03-07 05:26:10 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
#####################################################
## Convert EasyMocap results to TRC ##
#####################################################
Converts EasyMocap keypoints3D results to TRC files .
If several people are detected , writes one TRC file per person .
N . B . : If you run EasyMocap with a different model , edit KEYPOINT_NAMES
accordingly ( names and order of keypoints ) .
N . B . : EasyMocap currently attributes even IDs to the detected people ,
so the trc files with odd numbers may be empty . Left this way for it
to still work the day they fix it .
N . B . : Trc framerate is set to 1 by default .
Usage :
python - m trc_from_easymocap - i input_keypoint_dir
python - m trc_from_easymocap - i input_keypoint_dir - o output_trc_dir
import trc_from_easymocap ; trc_from_easymocap . trc_from_easymocap_func ( input_keypoint_dir = r ' <input_keypoint_dir> ' , output_trc_dir = r ' <output_trc_dir> ' )
'''
## CONSTANTS
KEYPOINT_NAMES = [ ' Nose ' , ' Neck ' , ' RShoulder ' , ' RElbow ' , ' RWrist ' , ' LShoulder ' , ' LElbow ' , ' LWrist ' , ' CHip ' , ' RHip ' , ' RKnee ' , ' RAnkle ' , ' LHip ' , ' LKnee ' , ' LAnkle ' , ' REye ' , ' LEye ' , ' REar ' , ' LEar ' , ' LBigToe ' , ' LSmallToe ' , ' LHeel ' , ' RBigToe ' , ' RSmallToe ' , ' RHeel ' ]
## INIT
import argparse
import os
import glob
import json
import numpy as np
import pandas as pd
## AUTHORSHIP INFORMATION
__author__ = " David Pagnon "
__copyright__ = " Copyright 2021, Pose2Sim "
__credits__ = [ " David Pagnon " ]
__license__ = " BSD 3-Clause License "
2024-07-10 16:12:57 +08:00
__version__ = " 0.9.4 "
2024-03-07 05:26:10 +08:00
__maintainer__ = " David Pagnon "
__email__ = " contact@david-pagnon.com "
__status__ = " Development "
## FUNCTIONS
def zup2yup ( Q ) :
'''
X - > Y , Y - > Z , Z - > X
'''
cols = list ( Q . columns )
cols = np . array ( [ [ cols [ i * 3 + 1 ] , cols [ i * 3 + 2 ] , cols [ i * 3 ] ] for i in range ( int ( len ( cols ) / 3 ) ) ] ) . flatten ( )
Q = Q [ cols ]
return Q
def max_persons ( keypoint_files ) :
'''
Max number of persons in easymocap results
'''
max_id = 0
for f in keypoint_files :
with open ( f , ' r ' ) as json_f :
js = json . load ( json_f )
for p in js :
if p [ ' id ' ] > max_id :
max_id = p [ ' id ' ]
max_id + = 1
return max_id
def df_from_easymocap ( keypoint_files , max_id ) :
'''
Stores keypoint_files data in a list of dataframes with the IDs given by EasyMocap .
'''
Q = [ [ ] for n in range ( max_id ) ]
for f in keypoint_files :
with open ( f , ' r ' ) as json_f :
js = json . load ( json_f )
idx_persons_in_frame = [ p [ ' id ' ] for p in js ]
for idx in range ( max_id ) :
if idx in idx_persons_in_frame :
x = [ p [ ' id ' ] for p in js ] . index ( idx )
keypoints3d_frame = np . array ( js [ x ] [ ' keypoints3d ' ] ) [ : , : 3 ] . flatten ( ) . tolist ( )
else :
keypoints3d_frame = [ np . nan ] * len ( KEYPOINT_NAMES ) * 3
Q [ idx ] . append ( keypoints3d_frame )
Q_df = [ pd . DataFrame ( Q [ idx ] ) for idx in range ( max_id ) ]
return Q_df
def write_trc ( Q_df , output_trc_dir , trc_root_name ) :
'''
Writes a list of dataframes in a directory with a given root name .
'''
for idx , Q in enumerate ( Q_df ) :
DataRate = CameraRate = OrigDataRate = 1
NumFrames = len ( Q )
NumMarkers = len ( KEYPOINT_NAMES )
header_trc = [ ' PathFileType \t 4 \t (X/Y/Z) \t ' + trc_root_name + str ( idx ) ,
' DataRate \t CameraRate \t NumFrames \t NumMarkers \t Units \t OrigDataRate \t OrigDataStartFrame \t OrigNumFrames ' ,
' \t ' . join ( map ( str , [ DataRate , CameraRate , NumFrames , NumMarkers , ' m ' , OrigDataRate , 0 , NumFrames ] ) ) ,
' Frame# \t Time \t ' + ' \t \t \t ' . join ( KEYPOINT_NAMES ) + ' \t \t ' ,
' \t \t ' + ' \t ' . join ( [ f ' X { i + 1 } \t Y { i + 1 } \t Z { i + 1 } ' for i in range ( len ( KEYPOINT_NAMES ) ) ] ) ]
Q = zup2yup ( Q_df [ idx ] )
Q . index = np . array ( range ( NumFrames ) ) + 1
Q . insert ( 0 , ' t ' , Q . index / DataRate )
trc_path = os . path . realpath ( os . path . join ( output_trc_dir , trc_root_name + str ( idx ) + ' .trc ' ) )
with open ( trc_path , ' w ' ) as trc_o :
[ trc_o . write ( line + ' \n ' ) for line in header_trc ]
Q . to_csv ( trc_o , sep = ' \t ' , index = True , header = None , lineterminator = ' \n ' )
def trc_from_easymocap_func ( * * kwargs ) :
'''
Converts EasyMocap keypoints3D results to TRC files .
If several people are detected , writes one TRC file per person .
N . B . : If you run EasyMocap with a different model , edit KEYPOINT_NAMES
accordingly ( names and order of keypoints ) .
N . B . : EasyMocap currently attributes even IDs to the detected people ,
so the trc files with odd numbers may be empty . Left this way for it
to still work the day they fix it .
N . B . : Trc framerate is set to 1 by default .
Usage :
trc_from_easymocap - i input_keypoint_dir
trc_from_easymocap - i input_keypoint_dir - o output_trc_dir
import trc_from_easymocap ; trc_from_easymocap . trc_from_easymocap_func ( input_keypoint_dir = r ' <input_keypoint_dir> ' , output_trc_dir = r ' <output_trc_dir> ' )
'''
input_keypoint_dir = kwargs . get ( ' input_keypoint_dir ' )
output_trc_dir = kwargs . get ( ' output_trc_dir ' )
input_keypoint_dir = os . path . abspath ( input_keypoint_dir )
output_trc_dir = os . path . abspath ( output_trc_dir ) if output_trc_dir else os . path . dirname ( input_keypoint_dir )
if not os . path . exists ( output_trc_dir ) : os . makedirs ( output_trc_dir )
trc_root_name = os . path . basename ( os . path . dirname ( os . path . dirname ( input_keypoint_dir ) ) )
keypoint_files = sorted ( glob . glob ( input_keypoint_dir + ' /*.json ' ) )
max_id = max_persons ( keypoint_files )
Q_df = df_from_easymocap ( keypoint_files , max_id )
write_trc ( Q_df , output_trc_dir = output_trc_dir , trc_root_name = trc_root_name )
if __name__ == ' __main__ ' :
parser = argparse . ArgumentParser ( )
parser . add_argument ( ' -i ' , ' --input_keypoint_dir ' , required = True , help = ' directory on input keypoints3D folder with EasyMocap json files ' )
parser . add_argument ( ' -o ' , ' --output_trc_dir ' , required = False , help = ' direction of the gait. If negative, you need to include an equal sign in the argument, eg -d=-Z ' )
kwargs = vars ( parser . parse_args ( ) )
trc_from_easymocap_func ( * * kwargs )