def get_dict_analogs(acq): if acq.IsEmptyAnalog(): return None sig_labels = [] sig_descs = [] sig_units = [] sig_offset = [] sig_scale = [] sig_gain = [] dict_sigs = {} dict_sigs.update({'DATA': {}}) for sig in btk.Iterate(acq.GetAnalogs()): name = sig.GetLabel() offset = sig.GetOffset() scale = sig.GetScale() unit = sig.GetUnit() desc = sig.GetDescription() gain = sig.GetGain() sig_labels.append(name) sig_descs.append(desc) sig_units.append(unit) sig_offset.append(offset) sig_scale.append(scale) sig_gain.append(gain) val = np.asarray(sig.GetValues().flatten(), dtype=np.float32) dict_sigs['DATA'].update({name: val}) dict_sigs.update({'LABELS': np.array(sig_labels, dtype=str)}) dict_sigs.update({'DESCRIPTIONS': np.array(sig_descs, dtype=str)}) dict_sigs.update({'UNITS': np.array(sig_units, dtype=str)}) dict_sigs.update({'RATE': np.float32(acq.GetAnalogFrequency())}) dict_sigs.update({'OFFSET': np.array(sig_offset, dtype=np.float32)}) dict_sigs.update({'SCALE': np.array(sig_scale, dtype=np.float32)}) dict_sigs.update({'GAIN': np.array(sig_gain, dtype=np.int32)}) dict_sigs.update({'RESOLUTION': np.int32(acq.GetAnalogResolution())}) return dict_sigs
def _GetEvents(acq): """ Helper function to read and sort the event collection from an acq object :param acq: (btkAcquisition) :return: (list) List of btkEvent objects """ event_list = [event for event in btk.Iterate(acq.GetEvents())] event_list.sort(key=lambda i:i.GetFrame()) return event_list
def _get_1_forceplate_data(plate): """Read data of a single forceplate from a c3d file. plate is an instance of btk.btkForcePlatform. """ READ_CHS = ['Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'] if plate.GetType() != 2: # Nexus should always write forceplates as type 2 raise GaitDataError('Only type 2 forceplates are supported for now') rawdata = dict() data = dict() for ch in btk.Iterate(plate.GetChannels()): label = ch.GetLabel()[-3:-1] # strip descriptor and plate number rawdata[label] = np.squeeze(ch.GetData().GetValues()) if not all([ch in rawdata for ch in READ_CHS]): logger.warning(f'could not read force/moment data for plate {plate}') return None F = np.stack([rawdata['Fx'], rawdata['Fy'], rawdata['Fz']], axis=1) M = np.stack([rawdata['Mx'], rawdata['My'], rawdata['Mz']], axis=1) # we need to calculate the center of pressure, since it's not in the C3D # dz is the plate thickness (from moment origin to physical origin) needed # for center of pressure calculations dz = np.abs(plate.GetOrigin()[2]) cop = center_of_pressure(F, M, dz) # in plate local coords Ftot = np.linalg.norm(F, axis=1) # locations of +x+y, -x+y, -x-y, +x-y plate corners in world coords # (in that order) cor = plate.GetCorners() wT = np.mean(cor, axis=1) # translation vector, plate -> world # upper and lower bounds of forceplate ub = np.max(cor, axis=1) lb = np.min(cor, axis=1) # plate unit vectors in world system px = cor[:, 0] - cor[:, 1] py = cor[:, 0] - cor[:, 3] pz = np.array([0, 0, -1]) P = np.stack([px, py, pz], axis=1) wR = P / np.linalg.norm(P, axis=0) # rotation matrix, plate -> world # check whether CoP stays inside forceplate area and clip if necessary cop_w = _change_coords(cop, wR, wT) cop_wx = np.clip(cop_w[:, 0], lb[0], ub[0]) cop_wy = np.clip(cop_w[:, 1], lb[1], ub[1]) if not (cop_wx == cop_w[:, 0]).all() and (cop_wy == cop_w[:, 1]).all(): logger.warning( 'center of pressure outside forceplate bounds, clipping to plate') cop[:, 0] = cop_wx cop[:, 1] = cop_wy # XXX moment and force transformations may still be wrong data['F'] = _change_coords(-F, wR, 0) # not sure why sign flip needed data['Ftot'] = Ftot data['M'] = _change_coords(-M, wR, 0) # not sure why sign flip needed data['CoP'] = cop_w data['wR'] = wR data['wT'] = wT data['plate_corners'] = cor.T return data
def GetMarkerNames(acq): """Function to show point's label on acquisition. :parameter: `acq` : (btkAcquisition) a btk acquisition instance :return: `marker_names` : (list) marker names :todo: regex """ marker_names = list() for it in btk.Iterate(acq.GetPoints()): if it.GetType() == btk.btkPoint.Marker and it.GetLabel()[0] != "*": marker_names.append(it.GetLabel()) return marker_names
def get_dict_events(acq): if acq.IsEmptyEvent(): return None dict_events = {} for ev in btk.Iterate(acq.GetEvents()): name = ev.GetLabel() context = ev.GetContext() desc = ev.GetDescription() fr = ev.GetFrame() dict_events.update({fr: {}}) dict_events[fr].update({'FRAME': fr}) dict_events[fr].update({'LABEL': name}) dict_events[fr].update({'CONTEXT': context}) dict_events[fr].update({'DESCRIPTION': desc}) return dict_events
def _get_analog_data(c3dfile, devname): """Read analog data from a c3d file. devname is matched against channel names. """ acq = _get_c3dacq(c3dfile) data = dict() chnames = [] for i in btk.Iterate(acq.GetAnalogs()): if i.GetDescription().find(devname) >= 0: if (chname := i.GetLabel()) in chnames: raise GaitDataError( 'Duplicate channel names in C3D file. Please rename your channels.' ) chnames.append(chname) data[chname] = np.squeeze(i.GetValues())
def get_dict_points(acq, blocked_nan=False, resid=False, tgt_types=None): if acq.IsEmptyPoint(): return None pt_types = None if tgt_types is None else set() if tgt_types is not None: for type in tgt_types: if type == 'Angle': pt_types.add(btk.btkPoint.Angle) elif type == 'Force': pt_types.add(btk.btkPoint.Force) elif type == 'Marker': pt_types.add(btk.btkPoint.Marker) elif type == 'Moment': pt_types.add(btk.btkPoint.Moment) elif type == 'Power': pt_types.add(btk.btkPoint.Power) elif type == 'Reaction': pt_types.add(btk.btkPoint.Reaction) elif type == 'Scalar': pt_types.append(btk.btkPoint.Scalar) pt_labels = [] pt_descs = [] dict_pts = {} dict_pts.update({'DATA': {}}) dict_pts['DATA'].update({'POS': {}}) if resid: dict_pts['DATA'].update({'RESID': {}}) for pt in btk.Iterate(acq.GetPoints()): if pt_types is not None and pt.GetType() not in pt_types: continue pt_name = pt.GetLabel() pt_pos = pt.GetValues() if blocked_nan or resid: pt_resid = pt.GetResiduals().flatten() if blocked_nan: pt_null_masks = np.where(np.isclose(pt_resid, -1), True, False) pt_pos[pt_null_masks,:] = np.nan pt_desc = pt.GetDescription() pt_labels.append(pt_name) pt_descs.append(pt_desc) dict_pts['DATA']['POS'].update({pt_name: np.asarray(pt_pos, dtype=np.float32)}) if resid: dict_pts['DATA']['RESID'].update({pt_name: np.asarray(pt_resid, dtype=np.float32)}) dict_pts.update({'LABELS': np.array(pt_labels, dtype=str)}) dict_pts.update({'DESCRIPTIONS': np.array(pt_descs, dtype=str)}) dict_pts.update({'UNITS': acq.GetPointUnit()}) dict_pts.update({'RATE': np.float32(acq.GetPointFrequency())}) dict_pts.update({'FRAME': np.linspace(acq.GetFirstFrame(), acq.GetLastFrame(), acq.GetPointFrameNumber(), dtype=np.int32)}) return dict_pts
def _get_analog_data(c3dfile, devname): """ Read analog data from a c3d file. devname is matched against channel names. """ acq = _get_c3dacq(c3dfile) data = dict() chnames = [] for i in btk.Iterate(acq.GetAnalogs()): if i.GetDescription().find(devname) >= 0: chname = i.GetLabel() chnames.append(chname) data[chname] = np.squeeze(i.GetValues()) if chnames: return { 't': np.arange(len(data[chname])) / acq.GetAnalogFrequency(), 'data': data, } else: raise GaitDataError('No matching analog channels found in data')
def _get_forceplate_data(c3dfile): """Read data of all forceplates from c3d file. See read_data.get_forceplate_data() for details. """ logger.debug(f'reading forceplate data from {c3dfile}') acq = _get_c3dacq(c3dfile) fpe = btk.btkForcePlatformsExtractor() fpe.SetInput(acq) fpe.Update() fpdata = list() for eclipse_ind, plate in enumerate(btk.Iterate(fpe.GetOutput()), 1): logger.debug(f'reading from plate {eclipse_ind}') data = _get_1_forceplate_data(plate) if data is not None: # generate the Eclipse key data['eclipse_key'] = f'FP{eclipse_ind}' fpdata.append(data) return fpdata
def get_point_names(acq, tgt_types=None): pt_names = [] pt_types = None if tgt_types is None else set() if tgt_types is not None: for type in tgt_types: if type == 'Angle': pt_types.add(btk.btkPoint.Angle) elif type == 'Force': pt_types.add(btk.btkPoint.Force) elif type == 'Marker': pt_types.add(btk.btkPoint.Marker) elif type == 'Moment': pt_types.add(btk.btkPoint.Moment) elif type == 'Power': pt_types.add(btk.btkPoint.Power) elif type == 'Reaction': pt_types.add(btk.btkPoint.Reaction) elif type == 'Scalar': pt_types.append(btk.btkPoint.Scalar) for pt in btk.Iterate(acq.GetPoints()): if pt_types is not None and pt.GetType() not in pt_types: continue pt_names.append(pt.GetLabel()) return pt_names
def get_metadata(c3dfile): """ Read trial and subject metadata """ trialname = os.path.basename(os.path.splitext(c3dfile)[0]) sessionpath = os.path.dirname(c3dfile) acq = _get_c3dacq(c3dfile) # frame offset (start of trial data in frames) offset = acq.GetFirstFrame() lastfr = acq.GetLastFrame() length = lastfr - offset + 1 # or acq.GetPointFrameNumber() framerate = acq.GetPointFrequency() analograte = acq.GetAnalogFrequency() samplesperframe = acq.GetNumberAnalogSamplePerFrame() # count forceplates fpe = btk.btkForcePlatformsExtractor() fpe.SetInput(acq) fpe.Update() n_forceplates = len(list(btk.Iterate(fpe.GetOutput()))) # get markers try: markers = _get_c3d_metadata_field(acq, 'POINT', 'LABELS') except RuntimeError: markers = list() # not sure what the '*xx' markers are, but delete them for now markers = [m for m in markers if m[0] != '*'] # get events rstrikes, lstrikes, rtoeoffs, ltoeoffs = [], [], [], [] for i in btk.Iterate(acq.GetEvents()): if i.GetLabel() == "Foot Strike": if i.GetContext() == "Right": rstrikes.append(i.GetFrame()) elif i.GetContext() == "Left": lstrikes.append(i.GetFrame()) else: raise GaitDataError("Unknown context on foot strike event") elif i.GetLabel() == "Foot Off": if i.GetContext() == "Right": rtoeoffs.append(i.GetFrame()) elif i.GetContext() == "Left": ltoeoffs.append(i.GetFrame()) else: raise GaitDataError("Unknown context on foot strike event") # get subject info try: name = _get_c3d_metadata_field(acq, 'SUBJECTS', 'NAMES')[0] except RuntimeError: logger.warning('Cannot get subject name') name = u'Unknown' try: par_names = _get_c3d_metadata_subfields(acq, 'PROCESSING') except RuntimeError: raise GaitDataError('cannot read metadata from %s' % c3dfile) subj_params = defaultdict(lambda: None) subj_params.update({par: _get_c3d_subject_param(acq, par) for par in par_names}) # sort events (may be in wrong temporal order, at least in c3d files) for li in [lstrikes, rstrikes, ltoeoffs, rtoeoffs]: li.sort() return { 'trialname': trialname, 'sessionpath': sessionpath, 'offset': offset, 'framerate': framerate, 'analograte': analograte, 'name': name, 'subj_params': subj_params, 'lstrikes': lstrikes, 'rstrikes': rstrikes, 'ltoeoffs': ltoeoffs, 'rtoeoffs': rtoeoffs, 'length': length, 'samplesperframe': samplesperframe, 'n_forceplates': n_forceplates, 'markers': markers, }
def compute(leg, Filename_In): m = re.match(Input_Dir + "(?P<name>.+).c3d", Filename_In) name = m.group('name').replace(" ", "-") output_file = "%s/%s%s.csv" % (Output_Dir, leg, name) print("Trying %s" % (Filename_In)) # Read files in .c3d and read data reader = btk.btkAcquisitionFileReader() reader.SetFilename(Filename_In) reader.Update() acq = reader.GetOutput() nFrames = acq.GetPointFrameNumber() first_frame = acq.GetFirstFrame() # Heel, Ankle, Hallux, Toe # 2 * 4 * 3 = 24 Marker Trajectories # 2 * 4 * 3 = 24 Velocity # 2 * 4 * 3 = 24 Acceleration markers = ["ANK", "TOE", "HLX", "HEE"] opposite = {'L': 'R', 'R': 'L'} # Check if there are any marker data in the file brk = True for point in btk.Iterate(acq.GetPoints()): if point.GetLabel() == "L" + markers[0]: brk = False break if brk: print("No Datain %s!" % (Filename_In, )) return # Marker Data extraction and filtering. traj = [None] * (len(markers) * 2) for i, v in enumerate(markers): try: traj[i] = acq.GetPoint(leg + v).GetValues() traj[len(markers) + i] = acq.GetPoint(opposite[leg] + v).GetValues() except: return traj[i][:, 0] = traj[i][:, 0] # * incrementX traj[len(markers) + i][:, 0] = traj[len(markers) + i][:, 0] # * incrementX traj[i][:, 2] = traj[i][:, 2] # * incrementX traj[len(markers) + i][:, 2] = traj[len(markers) + i][:, 2] # * incrementXq # filter then getting position, velocity and accleration filtered_traj = [data_filter(acq, ax, nFrames) for ax in traj] vel = [derivative(bx, nFrames) for bx in filtered_traj] acc = [derivative(cx, nFrames) for cx in vel] curves = np.concatenate(filtered_traj + vel + acc, axis=1) # Add events as output using annotation on data outputs = np.array([[0] * nFrames, [0] * nFrames]).T for event in btk.Iterate(acq.GetEvents()): if event.GetFrame() >= nFrames: print("Event happened too far") return if len(event.GetContext()) == 0: print("No events found") return if event.GetContext()[0] == leg: if event.GetLabel() == "Foot Strike": outputs[event.GetFrame() - first_frame, 0] = 1 elif event.GetLabel() == "Foot Off": outputs[event.GetFrame() - first_frame, 1] = 1 if (np.sum(outputs) == 0): print("No events in %s!" % (Filename_In, )) return arr = np.concatenate((curves, outputs), axis=1) print("Writing %s" % Filename_In) np.savetxt(output_file, arr, delimiter=',')
def get_forceplate_data(c3dfile): logger.debug('reading forceplate data from %s' % c3dfile) read_chs = ['Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'] acq = _get_c3dacq(c3dfile) fpe = btk.btkForcePlatformsExtractor() fpe.SetInput(acq) fpe.Update() fpdata = list() nplate = 0 for plate in btk.Iterate(fpe.GetOutput()): logger.debug('reading from plate %d' % nplate) nplate += 1 if plate.GetType() != 2: # Nexus should always write forceplates as type 2 raise GaitDataError('Only type 2 forceplates are supported for now') rawdata = dict() data = dict() for ch in btk.Iterate(plate.GetChannels()): label = ch.GetLabel()[-3:-1] # strip descriptor and plate number rawdata[label] = np.squeeze(ch.GetData().GetValues()) if not all([ch in rawdata for ch in read_chs]): logger.warning('could not read force/moment data for plate %d' % nplate) continue F = np.stack([rawdata['Fx'], rawdata['Fy'], rawdata['Fz']], axis=1) M = np.stack([rawdata['Mx'], rawdata['My'], rawdata['Mz']], axis=1) # this should be the plate thickness (from moment origin to physical # origin) needed for center of pressure calculations dz = np.abs(plate.GetOrigin()[2]) cop = center_of_pressure(F, M, dz) # in plate local coords Ftot = np.linalg.norm(F, axis=1) # locations of +x+y, -x+y, -x-y, +x-y plate corners in world coords # (in that order) cor = plate.GetCorners() wT = np.mean(cor, axis=1) # translation vector, plate -> world # upper and lower bounds of forceplate ub = np.max(cor, axis=1) lb = np.min(cor, axis=1) # plate unit vectors in world system px = cor[:, 0] - cor[:, 1] py = cor[:, 0] - cor[:, 3] pz = np.array([0, 0, -1]) P = np.stack([px, py, pz], axis=1) wR = P / np.linalg.norm(P, axis=0) # rotation matrix, plate -> world # check whether cop stays inside forceplate area and clip if necessary cop_w = change_coords(cop, wR, wT) cop_wx = np.clip(cop_w[:, 0], lb[0], ub[0]) cop_wy = np.clip(cop_w[:, 1], lb[1], ub[1]) if not (cop_wx == cop_w[:, 0]).all() and (cop_wy == cop_w[:, 1]).all(): logger.warning( 'center of pressure outside forceplate bounds, clipping to plate' ) cop[:, 0] = cop_wx cop[:, 1] = cop_wy # XXX moment and force transformations may still be wrong data['F'] = change_coords(-F, wR, 0) # not sure why sign flip needed data['Ftot'] = Ftot data['M'] = change_coords(-M, wR, 0) # not sure why sign flip needed data['CoP'] = cop_w data['upperbounds'] = ub data['lowerbounds'] = lb data['wR'] = wR data['wT'] = wT data['cor_full'] = cor.T fpdata.append(data) return fpdata
def _get_metadata(c3dfile): """Read trial and subject metadata from c3d file. See read_data.get_metadata() for details. """ c3dfile = Path(c3dfile) trialname = c3dfile.stem sessionpath = c3dfile.parent acq = _get_c3dacq(c3dfile) # frame offset (start of trial data in frames) offset = acq.GetFirstFrame() lastfr = acq.GetLastFrame() length = lastfr - offset + 1 # or acq.GetPointFrameNumber() framerate = acq.GetPointFrequency() analograte = acq.GetAnalogFrequency() samplesperframe = acq.GetNumberAnalogSamplePerFrame() # count forceplates fpe = btk.btkForcePlatformsExtractor() fpe.SetInput(acq) fpe.Update() n_forceplates = len(list(btk.Iterate(fpe.GetOutput()))) # get markers try: markers = _get_c3d_metadata_field(acq, 'POINT', 'LABELS') except RuntimeError: markers = list() # XXX: not sure what the '*xx' markers are, but delete them for now markers = [m for m in markers if m[0] != '*'] # get events events = GaitEvents() for i in btk.Iterate(acq.GetEvents()): fr = i.GetFrame() context = i.GetContext()[0] ev_type = i.GetLabel() if ev_type == 'Foot Strike': ev_type_ours = 'strike' elif ev_type == 'Foot Off': ev_type_ours = 'toeoff' else: ev_type_ours = ev_type fr_offset = fr - offset ev = GaitEvent(fr_offset, ev_type_ours, context) events.append(ev) # get subject info try: subj_name = _get_c3d_metadata_field(acq, 'SUBJECTS', 'NAMES')[0] except RuntimeError: logger.warning('Cannot get subject name') subj_name = 'Unknown' subj_params = defaultdict(lambda: None) try: par_names = _get_c3d_metadata_subfields(acq, 'PROCESSING') except RuntimeError: logger.warning( f'{c3dfile} is missing the PROCESSING section that contains ' 'subject info (bodyweight etc.)') else: subj_params.update( {par: _get_c3d_subject_param(acq, par) for par in par_names}) return { 'trialname': trialname, 'sessionpath': sessionpath, 'offset': offset, 'framerate': framerate, 'analograte': analograte, 'subject_name': subj_name, 'subj_params': subj_params, 'events': events, 'length': length, 'samplesperframe': samplesperframe, 'n_forceplates': n_forceplates, 'markers': markers, }
def param_spt(filename, side): reader = btk.btkAcquisitionFileReader() reader.SetFilename(filename) reader.Update() acq = reader.GetOutput() if side.lower() == "left": foot_marker = acq.GetPoint('LHEE').GetValues() foot_marker_ct = acq.GetPoint('RHEE').GetValues() side_cl = "right" side_letter = "L" elif side.lower() == "right": foot_marker = acq.GetPoint('RHEE').GetValues() foot_marker_ct = acq.GetPoint('LHEE').GetValues() side_cl = "left" side_letter = "R" # Initialisation des lists contenant les evenements FO = [] FO_CL = [] FS = [] FS_CL = [] for it in btk.Iterate(acq.GetEvents()): if it.GetContext().lower() == side: if it.GetLabel() == 'Foot Strike': FS.append(it.GetFrame()) elif it.GetLabel() == 'Foot Off': FO.append(it.GetFrame()) elif it.GetContext().lower() == side_cl: if it.GetLabel() == 'Foot Strike': FS_CL.append(it.GetFrame()) elif it.GetLabel() == 'Foot Off': FO_CL.append(it.GetFrame()) # Les evenements ne sont pas forcement organisé dans le bon ordre FO.sort() FO_CL.sort() FS.sort() FS_CL.sort() frq_point = float(acq.GetPointFrequency()) # On enleve tout les evenements qui sont avant le premier foot strike du coté étudié first_event = FS[0] first_frame = acq.GetFirstFrame() last_frame = acq.GetLastFrame() FS = [x - first_frame for x in FS if x >= first_event] FS_CL = [x - first_frame for x in FS_CL if x >= first_event] FO = [x - first_frame for x in FO if x >= first_event] FO_CL = [x - first_frame for x in FO_CL if x >= first_event] # Extraction de la longueur de jambe md = acq.GetMetaData() leg_lenght = md.FindChild("PROCESSING").value().FindChild( side_letter + 'LegLength').value().GetInfo().ToDouble()[0] / 1000.0 gravity = 9.81 # définition de la direction de marche point = acq.GetPoint('LPSI').GetValues() direction_walk = point[last_frame - first_frame, :] - point[0, :] direction_walk = np.argmax(np.abs(direction_walk)) point = acq.GetPoint('LPSI').GetValues() - acq.GetPoint('RPSI').GetValues() direction_width = np.argmax(np.abs(point[0, :])) param_spt = { "cycle_time": [], "cadence": [], "cadence_adm": [], "length_cycle": [], "length_cycle_adm": [], "walking_speed": [], "walking_speed_adm": [], "step_length": [], "step_length_adm": [], "step_sec": [], "step_width": [], "step_width_adm": [], "stance_phase_sec": [], "stance_phase_perc": [], "swing_phase_sec": [], "swing_phase_perc": [], "double_stance_sec": [], "double_stance_perc": [], "simple_stance_sec": [], "simple_stance_perc": [], "percentage_CTFO": [], "percentage_CTFS": [] } for ind_cycle in range(len(FS) - 1): nb_frame_cycle = float(FS[ind_cycle + 1] - FS[ind_cycle]) # Temps du cycle (s) cycle_time = (FS[ind_cycle + 1] - FS[ind_cycle]) / frq_point param_spt["cycle_time"].append(cycle_time) # Cadence (step/mn) cadence = 120.0 / cycle_time param_spt["cadence"].append(cadence) param_spt["cadence_adm"].append(cadence / np.sqrt(gravity / leg_lenght)) # Longueur du cycle (m) length_cycle = np.abs(foot_marker[FS[ind_cycle + 1], direction_walk] - foot_marker[FS[ind_cycle], direction_walk]) / 1000.0 param_spt["length_cycle"].append(length_cycle) param_spt["length_cycle_adm"].append(length_cycle / leg_lenght) # Vitesse de marche (m/s) walking_speed = cadence * length_cycle / 120.0 param_spt["walking_speed"].append(walking_speed) param_spt["walking_speed_adm"].append(walking_speed / np.sqrt(leg_lenght * gravity)) # Longueur du pas (m) step_length = np.abs(foot_marker_ct[FO[ind_cycle], direction_walk] - foot_marker[FS[ind_cycle], direction_walk]) / 1000.0 param_spt["step_length"].append(step_length) param_spt["step_length_adm"].append(step_length / leg_lenght) # Temps Pas (frame, sec) step_frame = FS_CL[ind_cycle] - FS[ind_cycle] step_sec = step_frame / frq_point param_spt["step_sec"].append(step_sec) # Largeur pas (m) step_width = np.abs(foot_marker_ct[FO[ind_cycle], direction_width] - foot_marker[FS[ind_cycle], direction_width]) / 1000.0 param_spt["step_width"].append(step_width) param_spt["step_width_adm"].append(step_width / leg_lenght) # Phase d'appui (frame, sec, pourcentage) stance_phase_frame = FO[ind_cycle] - FS[ind_cycle] stance_phase_sec = stance_phase_frame / frq_point stance_phase_perc = stance_phase_frame / nb_frame_cycle * 100 param_spt["stance_phase_sec"].append(stance_phase_sec) param_spt["stance_phase_perc"].append(stance_phase_perc) # Phase oscillante (frame, sec, pourcentage) swing_phase_frame = FS[ind_cycle + 1] - FO[ind_cycle] swing_phase_sec = swing_phase_frame / frq_point swing_phase_perc = swing_phase_frame / nb_frame_cycle * 100 param_spt["swing_phase_sec"].append(swing_phase_sec) param_spt["swing_phase_perc"].append(swing_phase_perc) # Double appui (frame, sec, pourcentage) double_stance_frame = (FO_CL[ind_cycle] - FS[ind_cycle] + FO[ind_cycle] - FS_CL[ind_cycle]) double_stance_sec = double_stance_frame / frq_point double_stance_perc = double_stance_frame / nb_frame_cycle * 100 param_spt["double_stance_sec"].append(double_stance_sec) param_spt["double_stance_perc"].append(double_stance_perc) # Simple appui (frame, sec, pourcentage) simple_stance_frame = FS_CL[ind_cycle] - FO_CL[ind_cycle] simple_stance_sec = simple_stance_frame / frq_point simple_stance_perc = simple_stance_frame / nb_frame_cycle * 100 param_spt["simple_stance_sec"].append(simple_stance_sec) param_spt["simple_stance_perc"].append(simple_stance_perc) # Calcul des evenements controlateral pour affichage cinématique CTFS_frame = FS_CL[ind_cycle] - FS[ind_cycle] CTFO_frame = FO_CL[ind_cycle] - FS[ind_cycle] CTFS_perc = CTFS_frame / nb_frame_cycle * 100 CTFO_perc = CTFO_frame / nb_frame_cycle * 100 param_spt["percentage_CTFS"].append(CTFS_perc) param_spt["percentage_CTFO"].append(CTFO_perc) return param_spt
RKneeAnglesNormaliseListY = np.array([]) RKneeAnglesNormaliseListZ = np.array([]) RAnkleAnglesNormaliseListX = np.array([]) RAnkleAnglesNormaliseListY = np.array([]) RAnkleAnglesNormaliseListZ = np.array([]) RFootProgressAnglesNormaliseListX = np.array([]) RFootProgressAnglesNormaliseListY = np.array([]) RFootProgressAnglesNormaliseListZ = np.array([]) for i in range(len(list)): PoseTalonGauche = [] PoseTalonDroit = [] DecollementPiedGauche = [] DecollementPiedDroit = [] for it in btk.Iterate(acq[i].GetEvents()): if (it.GetLabel() == "Foot Strike") and (it.GetContext() == "Left"): PoseTalonGauche.append(it.GetFrame()) if (it.GetLabel() == "Foot Strike") and (it.GetContext() == "Right"): PoseTalonDroit.append(it.GetFrame()) if (it.GetLabel() == "Foot Off") and (it.GetContext() == "Left"): DecollementPiedGauche.append(it.GetFrame()) if (it.GetLabel() == "Foot Off") and (it.GetContext() == "Right"): DecollementPiedDroit.append(it.GetFrame()) PoseTalonGauche.sort() PoseTalonDroit.sort() DecollementPiedGauche.sort() DecollementPiedDroit.sort() nb_cycle_gauche_cinematique = len(PoseTalonGauche) - 1
def extract_kinematics(leg, filename_in, sacr=False, lstm=True, turn=False): # Open c3d and read data reader = btk.btkAcquisitionFileReader() reader.SetFilename(filename_in) reader.Update() acq = reader.GetOutput() nframes = acq.GetPointFrameNumber() first_frame = acq.GetFirstFrame() end = acq.GetLastFrame() # Check if there is a FOG for event in btk.Iterate(acq.GetEvents()): if event.GetLabel() == 'FOG': end = event.GetFrame() nframes = end - first_frame metadata = acq.GetMetaData() # We extract only kinematics kinematics = ["HipAngles", "KneeAngles", "AnkleAngles"] markers = ["TOE", "KNE", "HEE"] # Check if there are any kinematics in the file brk = True for point in btk.Iterate(acq.GetPoints()): if point.GetLabel() == "L" + kinematics[0]: brk = False break if brk: print("No kinematics in:" + str(filename_in)) return # Add events as output outputs = np.array([[0] * nframes]).T for event in btk.Iterate(acq.GetEvents()): if first_frame < event.GetFrame() < end: if event.GetLabel() == "Foot Strike": if event.GetContext() == 'Left': outputs[event.GetFrame() - first_frame, 0] = 1 elif event.GetContext() == 'Right': outputs[event.GetFrame() - first_frame, 0] = 2 elif event.GetLabel() == "Foot Off": if event.GetContext() == 'Left': outputs[event.GetFrame() - first_frame, 0] = 3 elif event.GetContext() == 'Right': outputs[event.GetFrame() - first_frame, 0] = 4 if (np.sum(outputs) == 0): print("No events in:" + str(filename_in)) return positives = np.where(outputs > 0.5) if len(positives[0]) == 0: return None first_event = positives[0][0] # Combine kinematics into one big array opposite = {'L': 'R', 'R': 'L'} angles = [None] * (len(kinematics) * 2) for i, v in enumerate(kinematics): point = acq.GetPoint(leg + v) angles[i] = point.GetValues() angles[i] = angles[i][:nframes] point = acq.GetPoint(opposite[leg] + v) angles[len(kinematics) + i] = point.GetValues() angles[len(kinematics) + i] = angles[len(kinematics) + i][:nframes] print(filename_in) # Get the pelvis (if no SACR marker) if sacr: SACR_X = acq.GetPoint("SACR").GetValues()[:, 0] else: LPSI_X = acq.GetPoint("LPSI").GetValues()[:, 0] RPSI_X = acq.GetPoint("RPSI").GetValues()[:, 0] midPSI_X = (LPSI_X + RPSI_X) / 2 SACR_X = midPSI_X pos = [None] * (len(markers) * 2) pos_sacr_X = [None] * (len(markers) * 2) pos_sacr_Y = [None] * (len(markers) * 2) pos_sacr_Z = [None] * (len(markers) * 2) pos_sacr = [None] * (len(markers) * 2) for j, w in enumerate(markers): point = acq.GetPoint(leg + w) pos[j] = point.GetValues() pos_sacr_X[j] = point.GetValues()[:, 0] - SACR_X pos_sacr_Y[j] = point.GetValues()[:, 1] pos_sacr_Z[j] = point.GetValues()[:, 2] pos_sacr[j] = np.column_stack( (pos_sacr_X[j], pos_sacr_Y[j], pos_sacr_Z[j])) pos_sacr[j] = pos_sacr[j][:nframes] point = acq.GetPoint(opposite[leg] + w) pos[len(markers) + j] = point.GetValues() pos_sacr_X[len(markers) + j] = point.GetValues()[:, 0] - SACR_X pos_sacr_Y[len(markers) + j] = point.GetValues()[:, 1] pos_sacr_Z[len(markers) + j] = point.GetValues()[:, 2] pos_sacr[len(markers) + j] = np.column_stack( (pos_sacr_X[len(markers) + j], pos_sacr_Y[len(markers) + j], pos_sacr_Z[len(markers) + j])) pos_sacr[len(markers) + j] = pos_sacr[len(markers) + j][:nframes] # Low pass filter at 7Hz angles_lp = butter_lowpass_filter(np.hstack(angles), cutoff=7, fs=100) markers_lp = butter_lowpass_filter(np.hstack(pos_sacr), cutoff=7, fs=100) # Get derivatives angles_lp_vel = derivative(angles_lp, nframes) markers_lp_vel = derivative(markers_lp, nframes) angles = np.hstack((angles_lp, angles_lp_vel)) markers = np.hstack((markers_lp, markers_lp_vel)) if marker: curves = np.concatenate((angles, markers), axis=1) else: curves = angles arr = np.concatenate((curves, outputs), axis=1) # Remove data before and after first event minus some random int. This is for those trials that are not pre-cut. if sacr: positives = np.where(arr[:, 36] > 0.5) if len(positives[0]) == 0: return None first_event = positives[0][0] - random.randint(5, 15) last_event = positives[0][-1] + random.randint(5, 15) curves = curves[first_event:last_event] first_frame = first_event out = [curves, markers, angles, first_frame] return out
def kinematic(filename, side, extension): reader = btk.btkAcquisitionFileReader() reader.SetFilename(filename) reader.Update() acq = reader.GetOutput() if side.lower() == "left": side_letter = 'L' side_cl = "right" elif side.lower() == "right": side_letter = 'R' side_cl = "left" # Initialisation des lists contenant les evenements FO = [] FO_CL = [] FS = [] FS_CL = [] for it in btk.Iterate(acq.GetEvents()): if it.GetContext().lower() == side: if it.GetLabel() == 'Foot Strike': FS.append(it.GetFrame()) elif it.GetLabel() == 'Foot Off': FO.append(it.GetFrame()) elif it.GetContext().lower() == side_cl: if it.GetLabel() == 'Foot Strike': FS_CL.append(it.GetFrame()) elif it.GetLabel() == 'Foot Off': FO_CL.append(it.GetFrame()) FO.sort() FO_CL.sort() FS.sort() FS_CL.sort() # frq_point = float(acq.GetPointFrequency()) # On enleve tout les evenements qui sont avant le premier foot strike du coté étudié first_event = FS[0] first_frame = acq.GetFirstFrame() # last_frame = acq.GetLastFrame() FS = [x - first_frame for x in FS if x >= first_event] FS_CL = [x - first_frame for x in FS_CL if x >= first_event] FO = [x - first_frame for x in FO if x >= first_event] FO_CL = [x - first_frame for x in FO_CL if x >= first_event] # Initialisation nb_cycle = len(FS) - 1 kinematic = { "Pelvis_Fle": np.zeros((101, nb_cycle)), "Pelvis_Abd": np.zeros((101, nb_cycle)), "Pelvis_Ier": np.zeros((101, nb_cycle)), "Hip_Fle": np.zeros((101, nb_cycle)), "Hip_Abd": np.zeros((101, nb_cycle)), "Hip_Ier": np.zeros((101, nb_cycle)), "Knee_Fle": np.zeros((101, nb_cycle)), "Knee_Abd": np.zeros((101, nb_cycle)), "Knee_Ier": np.zeros((101, nb_cycle)), "Ankle_Fle": np.zeros((101, nb_cycle)), "Foot_Progression": np.zeros((101, nb_cycle)), "Foot_tilt": np.zeros((101, nb_cycle)) } for ind_cycle in range(nb_cycle): nb_frame = FS[ind_cycle + 1] - FS[ind_cycle] # paramètre pour l'interpolation sur 100 point x = np.linspace(0, nb_frame, 101) xp = np.linspace(0, nb_frame, nb_frame) # Pelvis f_flexion = acq.GetPoint(side_letter + 'PelvisAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] f_abduction = acq.GetPoint(side_letter + 'PelvisAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 1] f_rotation = acq.GetPoint(side_letter + 'PelvisAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 2] # if side == "left": # f_abduction = -f_abduction # f_rotation = -f_rotation kinematic["Pelvis_Fle"][:, ind_cycle] = np.interp(x, xp, f_flexion) kinematic["Pelvis_Abd"][:, ind_cycle] = np.interp(x, xp, f_abduction) kinematic["Pelvis_Ier"][:, ind_cycle] = np.interp(x, xp, f_rotation) # Hip f_flexion = acq.GetPoint(side_letter + 'HipAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] f_abduction = acq.GetPoint(side_letter + 'HipAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 1] f_rotation = acq.GetPoint(side_letter + 'HipAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 2] kinematic["Hip_Fle"][:, ind_cycle] = np.interp(x, xp, f_flexion) kinematic["Hip_Abd"][:, ind_cycle] = np.interp(x, xp, f_abduction) kinematic["Hip_Ier"][:, ind_cycle] = np.interp(x, xp, f_rotation) # Knee f_flexion = acq.GetPoint(side_letter + 'KneeAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] f_abduction = acq.GetPoint(side_letter + 'KneeAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 1] f_rotation = acq.GetPoint(side_letter + 'KneeAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 2] kinematic["Knee_Fle"][:, ind_cycle] = np.interp(x, xp, f_flexion) kinematic["Knee_Abd"][:, ind_cycle] = np.interp(x, xp, f_abduction) kinematic["Knee_Ier"][:, ind_cycle] = np.interp(x, xp, f_rotation) # Ankle f_flexion = acq.GetPoint(side_letter + 'AnkleAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] f_progression = acq.GetPoint(side_letter + 'FootProgressAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 2] f_tilt = acq.GetPoint(side_letter + 'FootProgressAngles' + extension).GetValues()[FS[ind_cycle]:FS[ind_cycle + 1], 0] f_tilt = -f_tilt - 90 kinematic["Ankle_Fle"][:, ind_cycle] = np.interp(x, xp, f_flexion) kinematic["Foot_Progression"][:, ind_cycle] = np.interp( x, xp, f_progression) kinematic["Foot_tilt"][:, ind_cycle] = np.interp(x, xp, f_tilt) return kinematic
def kinetic(filename, side, extension): [FP1, FP2] = extraction_enf(filename) reader = btk.btkAcquisitionFileReader() reader.SetFilename(filename) reader.Update() acq = reader.GetOutput() plateform_valid = [side == FP1, side == FP2] if side.lower() == "left": side_letter = 'L' side_cl = "right" elif side.lower() == "right": side_letter = 'R' side_cl = "left" # Initialisation des lists contenant les evenements FO = [] FO_CL = [] FS = [] FS_CL = [] for it in btk.Iterate(acq.GetEvents()): if it.GetContext().lower() == side: if it.GetLabel() == 'Foot Strike': FS.append(it.GetFrame()) elif it.GetLabel() == 'Foot Off': FO.append(it.GetFrame()) elif it.GetContext().lower() == side_cl: if it.GetLabel() == 'Foot Strike': FS_CL.append(it.GetFrame()) elif it.GetLabel() == 'Foot Off': FO_CL.append(it.GetFrame()) FO.sort() FO_CL.sort() FS.sort() FS_CL.sort() frq_point = float(acq.GetPointFrequency()) frq_analog = float(acq.GetAnalogFrequency()) factor_point_analog = frq_analog / frq_point # On enleve tout les evenements qui sont avant le premier foot strike du coté étudié first_event = FS[0] first_frame = acq.GetFirstFrame() # last_frame = acq.GetLastFrame() FS = [x - first_frame for x in FS if x >= first_event] FS_CL = [x - first_frame for x in FS_CL if x >= first_event] FO = [x - first_frame for x in FO if x >= first_event] FO_CL = [x - first_frame for x in FO_CL if x >= first_event] # Coefficient d'adimension pour les moments md = acq.GetMetaData() leg_lenght = md.FindChild("PROCESSING").\ value().FindChild(side_letter + 'LegLength').\ value().GetInfo().ToDouble()[0] / 1000.0 body_mass = md.FindChild("PROCESSING").\ value().FindChild('Bodymass').\ value().GetInfo().ToDouble()[0] gravity = 9.81 # In nexus the unit of the moment is Nmm / kg and in the Schwartz norm the data are # in N m/kg (just divided by the mass of the subject) # coeff_moment = leg_lenght * body_mass * gravity coeff_moment = 1000 # Initialisation # nb_cycle = len(FS) - 1 fz1 = acq.GetAnalog("Fz1").GetValues() fz2 = acq.GetAnalog("Fz2").GetValues() # nb_cycle = sum(plateform_valid) nb_cycle = len(FS) - 1 cycle_valid = 0 for ind_cycle in range(nb_cycle): init_cycle = FS[ind_cycle] end_cycle = FS[ind_cycle + 1] nb_frame = end_cycle - init_cycle nbr_frame_fz1 = sum( np.abs(fz1[int(init_cycle * factor_point_analog ):int(end_cycle * factor_point_analog)]) > 5 ) / factor_point_analog nbr_frame_fz2 = sum( np.abs(fz2[int(init_cycle * factor_point_analog ):int(end_cycle * factor_point_analog)]) > 5 ) / factor_point_analog condition_Plat1 = (nbr_frame_fz1 / float(nb_frame)) > 0.15 and plateform_valid[0] condition_Plat2 = (nbr_frame_fz2 / float(nb_frame)) > 0.15 and plateform_valid[1] if condition_Plat1 or condition_Plat2: cycle_valid += 1 kinematic = { "Pelvis_Fle": np.zeros((101, cycle_valid)), "Pelvis_Abd": np.zeros((101, cycle_valid)), "Pelvis_Ier": np.zeros((101, cycle_valid)), "Hip_Fle": np.zeros((101, cycle_valid)), "Hip_Abd": np.zeros((101, cycle_valid)), "Hip_Ier": np.zeros((101, cycle_valid)), "Knee_Fle": np.zeros((101, cycle_valid)), "Knee_Abd": np.zeros((101, cycle_valid)), "Knee_Ier": np.zeros((101, cycle_valid)), "Ankle_Fle": np.zeros((101, cycle_valid)), "Foot_Progression": np.zeros((101, cycle_valid)), "Foot_tilt": np.zeros((101, cycle_valid)) } kinetic = { "Pelvis_Abd": np.zeros((101, cycle_valid)), "Hip_Abd": np.zeros((101, cycle_valid)), "Knee_Abd": np.zeros((101, cycle_valid)), "Hip_Fle": np.zeros((101, cycle_valid)), "Knee_Fle": np.zeros((101, cycle_valid)), "Ankle_Fle": np.zeros((101, cycle_valid)), "Hip_Power": np.zeros((101, cycle_valid)), "Knee_Power": np.zeros((101, cycle_valid)), "Ankle_Power": np.zeros((101, cycle_valid)), "Normalised_Ground_Reaction_X": np.zeros((101, cycle_valid)), "Normalised_Ground_Reaction_Y": np.zeros((101, cycle_valid)), "Normalised_Ground_Reaction_Z": np.zeros((101, cycle_valid)), "Hip_Moment": np.zeros((101, cycle_valid)), "Knee_Moment": np.zeros((101, cycle_valid)), "Ankle_Moment": np.zeros((101, cycle_valid)), "Hip_Moment_abd": np.zeros((101, cycle_valid)), "Knee_Moment_abd": np.zeros((101, cycle_valid)), "Ankle_Moment_abd": np.zeros((101, cycle_valid)) } cycle_valid = 0 for ind_cycle in range(nb_cycle): init_cycle = FS[ind_cycle] end_cycle = FS[ind_cycle + 1] nb_frame = end_cycle - init_cycle nbr_frame_fz1 = sum( np.abs(fz1[int(init_cycle * factor_point_analog ):int(end_cycle * factor_point_analog)]) > 5 ) / factor_point_analog nbr_frame_fz2 = sum( np.abs(fz2[int(init_cycle * factor_point_analog ):int(end_cycle * factor_point_analog)]) > 5 ) / factor_point_analog condition_Plat1 = (nbr_frame_fz1 / float(nb_frame)) > 0.15 and plateform_valid[0] condition_Plat2 = (nbr_frame_fz2 / float(nb_frame)) > 0.15 and plateform_valid[1] if condition_Plat1 or condition_Plat2: # paramètre pour l'interpolation sur 100 point x = np.linspace(0, nb_frame, 101) xp = np.linspace(0, nb_frame, nb_frame) # Pelvis print side_letter + 'PelvisAngles' + extension f_flexion = acq.GetPoint(side_letter + 'PelvisAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] f_abduction = acq.GetPoint(side_letter + 'PelvisAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 1] f_rotation = acq.GetPoint(side_letter + 'PelvisAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 2] kinematic["Pelvis_Fle"][:, cycle_valid] = np.interp(x, xp, f_flexion) kinematic["Pelvis_Abd"][:, cycle_valid] = np.interp( x, xp, f_abduction) kinematic["Pelvis_Ier"][:, cycle_valid] = np.interp( x, xp, f_rotation) kinetic["Pelvis_Abd"][:, cycle_valid] = np.interp(x, xp, f_abduction) # Hip f_flexion = acq.GetPoint(side_letter + 'HipAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] f_abduction = acq.GetPoint(side_letter + 'HipAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 1] f_rotation = acq.GetPoint(side_letter + 'HipAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 2] kinematic["Hip_Fle"][:, cycle_valid] = np.interp(x, xp, f_flexion) kinematic["Hip_Abd"][:, cycle_valid] = np.interp(x, xp, f_abduction) kinematic["Hip_Ier"][:, cycle_valid] = np.interp(x, xp, f_rotation) kinetic["Hip_Fle"][:, cycle_valid] = np.interp(x, xp, f_flexion) kinetic["Hip_Abd"][:, cycle_valid] = np.interp(x, xp, f_abduction) # Knee f_flexion = acq.GetPoint(side_letter + 'KneeAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] f_abduction = acq.GetPoint(side_letter + 'KneeAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 1] f_rotation = acq.GetPoint(side_letter + 'KneeAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 2] kinematic["Knee_Fle"][:, cycle_valid] = np.interp(x, xp, f_flexion) kinematic["Knee_Abd"][:, cycle_valid] = np.interp(x, xp, f_abduction) kinematic["Knee_Ier"][:, cycle_valid] = np.interp(x, xp, f_rotation) kinetic["Knee_Fle"][:, cycle_valid] = np.interp(x, xp, f_flexion) kinetic["Knee_Abd"][:, cycle_valid] = np.interp(x, xp, f_abduction) # Ankle f_flexion = acq.GetPoint(side_letter + 'AnkleAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] f_progression = acq.GetPoint( side_letter + 'FootProgressAngles' + extension).GetValues()[FS[ind_cycle]:FS[ind_cycle + 1], 2] f_tilt = acq.GetPoint(side_letter + 'FootProgressAngles' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] f_tilt = -f_tilt - 90 kinematic["Ankle_Fle"][:, cycle_valid] = np.interp(x, xp, f_flexion) kinematic["Foot_Progression"][:, cycle_valid] = np.interp( x, xp, f_progression) kinematic["Foot_tilt"][:, cycle_valid] = np.interp(x, xp, f_tilt) kinetic["Ankle_Fle"][:, cycle_valid] = np.interp(x, xp, f_flexion) # kinetic power_hip = acq.GetPoint(side_letter + 'HipPower' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 2] power_knee = acq.GetPoint(side_letter + 'KneePower' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 2] power_ankle = acq.GetPoint(side_letter + 'AnklePower' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 2] kinetic["Hip_Power"][:, cycle_valid] = np.interp(x, xp, power_hip) kinetic["Knee_Power"][:, cycle_valid] = np.interp(x, xp, power_knee) kinetic["Ankle_Power"][:, cycle_valid] = np.interp( x, xp, power_ankle) normal_GRF_X = acq.GetPoint(side_letter + 'NormalisedGRF').GetValues()[ FS[ind_cycle]:FO[ind_cycle], 0] normal_GRF_X = np.append( normal_GRF_X, np.zeros((FS[ind_cycle + 1] - FO[ind_cycle], 1))) normal_GRF_Y = acq.GetPoint(side_letter + 'NormalisedGRF').GetValues()[ FS[ind_cycle]:FO[ind_cycle], 1] normal_GRF_Y = np.append( normal_GRF_Y, np.zeros((FS[ind_cycle + 1] - FO[ind_cycle], 1))) normal_GRF_Z = acq.GetPoint(side_letter + 'NormalisedGRF').GetValues()[ FS[ind_cycle]:FO[ind_cycle], 2] normal_GRF_Z = np.append( normal_GRF_Z, np.zeros((FS[ind_cycle + 1] - FO[ind_cycle], 1))) kinetic["Normalised_Ground_Reaction_X"][:, cycle_valid] = -np.interp( x, xp, normal_GRF_X) kinetic["Normalised_Ground_Reaction_Y"][:, cycle_valid] = np.interp( x, xp, normal_GRF_Y) kinetic["Normalised_Ground_Reaction_Z"][:, cycle_valid] = np.interp( x, xp, normal_GRF_Z) moment_hip = acq.GetPoint(side_letter + 'HipMoment' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] moment_knee = acq.GetPoint(side_letter + 'KneeMoment' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] moment_ankle = acq.GetPoint(side_letter + 'AnkleMoment' + extension).GetValues()[ FS[ind_cycle]:FS[ind_cycle + 1], 0] kinetic["Hip_Moment"][:, cycle_valid] = np.interp( x, xp, moment_hip) / coeff_moment kinetic["Knee_Moment"][:, cycle_valid] = np.interp( x, xp, moment_knee) / coeff_moment kinetic["Ankle_Moment"][:, cycle_valid] = np.interp( x, xp, moment_ankle) / coeff_moment moment_hip_abd = acq.GetPoint( side_letter + 'HipMoment' + extension).GetValues()[FS[ind_cycle]:FS[ind_cycle + 1], 1] moment_knee_abd = acq.GetPoint( side_letter + 'KneeMoment' + extension).GetValues()[FS[ind_cycle]:FS[ind_cycle + 1], 1] moment_ankle_abd = acq.GetPoint( side_letter + 'AnkleMoment' + extension).GetValues()[FS[ind_cycle]:FS[ind_cycle + 1], 1] kinetic["Hip_Moment_abd"][:, cycle_valid] = np.interp( x, xp, moment_hip_abd) / coeff_moment kinetic["Knee_Moment_abd"][:, cycle_valid] = np.interp( x, xp, moment_knee_abd) / coeff_moment kinetic["Ankle_Moment_abd"][:, cycle_valid] = np.interp( x, xp, moment_ankle_abd) / coeff_moment cycle_valid += 1 return [kinematic, kinetic]
def extract_kinematics(leg, filename_in): print("Trying %s" % (filename_in)) # Open c3d and read data reader = btk.btkAcquisitionFileReader() reader.SetFilename(filename_in) reader.Update() acq = reader.GetOutput() nframes = acq.GetPointFrameNumber() first_frame = acq.GetFirstFrame() metadata = acq.GetMetaData() rate = int( metadata.FindChild('POINT').value().FindChild( 'RATE').value().GetInfo().ToDouble()[0]) if rate != 120: return # We extract only kinematics kinematics = [ "HipAngles", "KneeAngles", "AnkleAngles", "PelvisAngles", "FootProgressAngles" ] markers = ["ANK", "TOE", "KNE", "ASI", "HEE"] # Cols # 2 * 5 * 3 = 30 kinematics # 2 * 5 * 3 = 30 marker trajectories # 2 * 5 * 3 = 30 marker trajectory derivatives # 3 * 3 = 9 extra trajectories outputs = np.array([[0] * nframes, [0] * nframes]).T # Check if there are any kinematics in the file brk = True for point in btk.Iterate(acq.GetPoints()): if point.GetLabel() == "L" + kinematics[0]: brk = False break if brk: print("No kinematics in %s!" % (filename, )) return # Combine kinematics into one big array opposite = {'L': 'R', 'R': 'L'} angles = [None] * (len(kinematics) * 2) for i, v in enumerate(kinematics): point = acq.GetPoint(leg + v) angles[i] = point.GetValues() point = acq.GetPoint(opposite[leg] + v) angles[len(kinematics) + i] = point.GetValues() # Get the pelvis LASI = acq.GetPoint("LASI").GetValues() RASI = acq.GetPoint("RASI").GetValues() midASI = (LASI + RASI) / 2 # incrementX = 1 if midASI[100][0] > midASI[0][0] else -1 traj = [None] * (len(markers) * 4 + 3) for i, v in enumerate(markers): try: traj[i] = acq.GetPoint(leg + v).GetValues() - midASI traj[len(markers) + i] = acq.GetPoint(opposite[leg] + v).GetValues() - midASI except: print("Error while reading marker data: %d, %s" % (i, v)) return traj[i][:, 0] = traj[i][:, 0] #* incrementX traj[len(markers) + i][:, 0] = traj[len(markers) + i][:, 0] #* incrementX traj[i][:, 2] = traj[i][:, 2] #* incrementX traj[len(markers) + i][:, 2] = traj[len(markers) + i][:, 2] #* incrementX for i in range(len(markers) * 2): traj[len(markers) * 2 + i] = derivative(traj[i], nframes) midASI = midASI #* incrementX midASIvel = derivative(midASI, nframes) midASIacc = derivative(midASIvel, nframes) traj[len(markers) * 4] = midASI traj[len(markers) * 4 + 1] = midASIvel traj[len(markers) * 4 + 2] = midASIacc curves = np.concatenate(angles + traj, axis=1) # Plot each component of the big array # for i in range(3 * len(kinematics)): # plt.plot(range(nframes), curves[:,i]) # Add events as output for event in btk.Iterate(acq.GetEvents()): if event.GetFrame() >= nframes: print("Event happened too far") return if len(event.GetContext()) == 0: print("No events") return # if event.GetContext()[0] == leg: if event.GetLabel() == "Foot Strike": outputs[event.GetFrame() - first_frame, 0] = 1 elif event.GetLabel() == "Foot Off": outputs[event.GetFrame() - first_frame, 1] = 1 print(event.GetLabel(), event.GetContext(), event.GetFrame(), event.GetFrame() - first_frame) if (np.sum(outputs) == 0): print("No events in %s!" % (filename, )) return arr = np.concatenate((curves, outputs), axis=1) return arr
def get_analog_names(acq): sig_names = [] for sig in btk.Iterate(acq.GetAnalogs()): sig_names.append(sig.GetLabel()) return sig_names
def _get_c3d_metadata_subfields(acq, field): """Return names of C3D metadata subfields for a given field""" meta = acq.GetMetaData() meta_s = meta.GetChild(field) return [f.GetLabel() for f in btk.Iterate(meta_s)]
def get_fp_output(acq, threshold=0.0, filt_fc=None, filt_order=2, cop_nan_to_num=True): pfe = btk.btkForcePlatformsExtractor() pfe.SetInput(acq) pfe.Update() pfc = pfe.GetOutput() if pfc.IsEmpty(): return None point_unit = acq.GetPointUnit() point_scale = 1.0 if point_unit=='m' else 0.001 analog_fps = acq.GetAnalogFrequency() rgx_fp = re.compile(r'\S*(\d*[FMP]\d*[XxYyZz]\d*)') fp_output = {} fp_idx = 0 for fp in btk.Iterate(pfc): fp_type = fp.GetType() # force plate location info fp_org_raw = np.squeeze(fp.GetOrigin())*point_scale fp_z_check = -1.0 if fp_org_raw[2]>0 else 1.0 if fp_type == 1: o_x = 0.0 o_y = 0.0 o_z = (-1.0)*fp_org_raw[2]*fp_z_check elif fp_type in [2, 4]: o_x = (-1.0)*fp_org_raw[0]*fp_z_check o_y = (-1.0)*fp_org_raw[1]*fp_z_check o_z = (-1.0)*fp_org_raw[2]*fp_z_check elif fp_type == 3: o_x = 0.0 o_y = 0.0 o_z = (-1.0)*fp_org_raw[2]*fp_z_check fp_len_a = np.abs(fp_org_raw[0]) fp_len_b = np.abs(fp_org_raw[1]) fp_corners = fp.GetCorners().T*point_scale # fp_corners[0] #(+x, +y) # fp_corners[1] #(-x, +y) # fp_corners[2] #(-x, -y) # fp_corners[3] #(+x, -y) fp_cen = np.mean(fp_corners, axis=0) fp_len_x = (np.linalg.norm(fp_corners[0]-fp_corners[1])+np.linalg.norm(fp_corners[3]-fp_corners[2]))*0.5 fp_len_y = (np.linalg.norm(fp_corners[0]-fp_corners[3])+np.linalg.norm(fp_corners[1]-fp_corners[2]))*0.5 fp_p0 = fp_cen fp_p1 = 0.5*(fp_corners[0]+fp_corners[3]) fp_p2 = 0.5*(fp_corners[0]+fp_corners[1]) fp_v0 = fp_p1-fp_p0 fp_v1 = fp_p2-fp_p0 fp_v0_u = fp_v0/np.linalg.norm(fp_v0) fp_v1_u = fp_v1/np.linalg.norm(fp_v1) fp_v2 = np.cross(fp_v0_u, fp_v1_u) fp_v2_u = fp_v2/np.linalg.norm(fp_v2) fp_v_z = fp_v2_u fp_v_x = fp_v0_u fp_v_y = np.cross(fp_v_z, fp_v_x) fp_rot_mat = np.column_stack([fp_v_x, fp_v_y, fp_v_z]) # force plate force/moment info fp_data = {} ch_data = {} ch_scale = {} # for ch in btk.Iterate(fp.GetChannels()): fp_cnt_chs = fp.GetChannelNumber() if filt_fc is None: filt_fcs = [None]*fp_cnt_chs elif type(filt_fc) in [int, float]: filt_fcs = [float(filt_fc)]*fp_cnt_chs elif type(filt_fc) in [list, tuple]: filt_fcs = list(filt_fc) elif type(filt_fc)==np.ndarray: if len(filt_fc)==1: filt_fcs = [filt_fc.item()]*fp_cnt_chs else: filt_fcs = filt_fc.tolist() for ch_idx in range(fp_cnt_chs): ch_name = fp.GetChannel(ch_idx).GetLabel() ch = acq.GetAnalog(ch_name) fm_name = str.upper(rgx_fp.findall(ch.GetLabel())[0]) # assign channel names if fp_type == 1: # assume that the order of input analog channels are as follows: # 'FX', 'FY', 'FZ', 'PX', 'PY', 'TZ' label = ['FX', 'FY', 'FZ', 'PX', 'PY', 'TZ'][ch_idx] elif fp_type in [2, 4]: label = re.sub(r'\d', r'', fm_name) elif fp_type == 3: # assume that the order of input analog channels are as follows: # 'FX12', 'FX34', 'FY14', 'FY23', 'FZ1', 'FZ2', 'FZ3', 'FZ4' label = ['FX12', 'FX34', 'FY14', 'FY23', 'FZ1', 'FZ2', 'FZ3', 'FZ4'][ch_idx] # assign channel scale factors if fp_type == 1: if label.startswith('F'): # assume that the force unit is 'N' ch_scale[label] = 1.0 elif label.startswith('T'): # assume that the torque unit is 'Nmm' ch_scale[label] = 0.001 if ch.GetUnit()=='Nm': ch_scale[label] = 1.0 elif label.startswith('P'): # assume that the position unit is 'mm' ch_scale[label] = 0.001 if ch.GetUnit()=='m': ch_scale[label] = 1.0 elif fp_type in [2, 3, 4]: if label.startswith('F'): # assume that the force unit is 'N' ch_scale[label] = 1.0 elif label.startswith('M'): # assume taht the torque unit is 'Nmm' ch_scale[label] = 0.001 if ch.GetUnit()=='Nm': ch_scale[label] = 1.0 # assign channel values lp_fc = filt_fcs[ch_idx] if lp_fc is None: ch_data[label] = np.squeeze(ch.GetData().GetValues()) else: ch_data[label] = filt_bw_lp(np.squeeze(ch.GetData().GetValues()), lp_fc, analog_fps, order=filt_order) if fp_type == 1: cop_l_x_in = ch_data['PX']*ch_scale['PX'] cop_l_y_in = ch_data['PY']*ch_scale['PY'] t_z_in = ch_data['TZ']*ch_scale['TZ'] fx = ch_data['FX']*ch_scale['FX'] fy = ch_data['FY']*ch_scale['FY'] fz = ch_data['FZ']*ch_scale['FZ'] mx = (cop_l_y_in-o_y)*fz+o_z*fy my = -o_z*fx-(cop_l_x_in-o_x)*fz mz = (cop_l_x_in-o_x)*fy-(cop_l_y_in-o_y)*fx+t_z_in f_raw = np.stack([fx, fy, fz], axis=1) m_raw = np.stack([mx, my, mz], axis=1) elif fp_type == 2: f_raw = np.stack([ch_data['FX']*ch_scale['FX'], ch_data['FY']*ch_scale['FY'], ch_data['FZ']*ch_scale['FZ']], axis=1) m_raw = np.stack([ch_data['MX']*ch_scale['MX'], ch_data['MY']*ch_scale['MY'], ch_data['MZ']*ch_scale['MZ']], axis=1) elif fp_type == 4: fp_cal_mat = fp.GetCalMatrix() fm_local = np.stack([ch_data['FX'], ch_data['FY'], ch_data['FZ'], ch_data['MX'], ch_data['MY'], ch_data['MZ']], axis=1) fm_calib = np.dot(fp_cal_mat, fm_local.T).T f_raw = np.stack([fm_calib[:,0]*ch_scale['FX'], fm_calib[:,1]*ch_scale['FY'], fm_calib[:,2]*ch_scale['FZ']], axis=1) m_raw = np.stack([fm_calib[:,3]*ch_scale['MX'], fm_calib[:,4]*ch_scale['MY'], fm_calib[:,5]*ch_scale['MZ']], axis=1) elif fp_type == 3: fx12 = ch_data['FX12']*ch_scale['FX12'] fx34 = ch_data['FX34']*ch_scale['FX34'] fy14 = ch_data['FY14']*ch_scale['FY14'] fy23 = ch_data['FY23']*ch_scale['FY23'] fz1 = ch_data['FZ1']*ch_scale['FZ1'] fz2 = ch_data['FZ2']*ch_scale['FZ2'] fz3 = ch_data['FZ3']*ch_scale['FZ3'] fz4 = ch_data['FZ4']*ch_scale['FZ4'] fx = fx12+fx34 fy = fy14+fy23 fz = fz1+fz2+fz3+fz4 mx = fp_len_b*(fz1+fz2-fz3-fz4) my = fp_len_a*(-fz1+fz2+fz3-fz4) mz = fp_len_b*(-fx12+fx34)+fp_len_a*(fy14-fy23) f_raw = np.stack([fx, fy, fz], axis=1) m_raw = np.stack([mx, my, mz], axis=1) zero_vals = np.zeros((f_raw.shape[0]), dtype=np.float32) fm_skip_mask = np.abs(f_raw[:,2])<=threshold f_sensor_local = f_raw.copy() m_sensor_local = m_raw.copy() # filter local values by threshold f_sensor_local[fm_skip_mask,:] = 0.0 m_sensor_local[fm_skip_mask,:] = 0.0 f_x = f_sensor_local[:,0] f_y = f_sensor_local[:,1] f_z = f_sensor_local[:,2] m_x = m_sensor_local[:,0] m_y = m_sensor_local[:,1] m_z = m_sensor_local[:,2] with np.errstate(invalid='ignore'): f_z_adj = np.where(fm_skip_mask, np.inf, f_z) cop_l_x = np.where(fm_skip_mask, np.nan, np.clip((-m_y+(-o_z)*f_x)/f_z_adj+o_x, -fp_len_x*0.5, fp_len_x*0.5)) cop_l_y = np.where(fm_skip_mask, np.nan, np.clip((m_x+(-o_z)*f_y)/f_z_adj+o_y, -fp_len_y*0.5, fp_len_y*0.5)) cop_l_z = np.where(fm_skip_mask, np.nan, zero_vals) if cop_nan_to_num: cop_l_x = np.nan_to_num(cop_l_x) cop_l_y = np.nan_to_num(cop_l_y) cop_l_z = np.nan_to_num(cop_l_z) t_z = m_z-(cop_l_x-o_x)*f_y+(cop_l_y-o_y)*f_x # values for the force plate local output m_cop_local = np.stack([zero_vals, zero_vals, t_z], axis=1) cop_surf_local = np.stack([cop_l_x, cop_l_y, cop_l_z], axis=1) f_surf_local = f_sensor_local m_surf_local = np.cross(np.array([o_x, o_y, o_z], dtype=np.float32), f_sensor_local)+m_sensor_local # values for the force plate global output m_cop_global = np.dot(fp_rot_mat, m_cop_local.T).T cop_surf_global = np.dot(fp_rot_mat, cop_surf_local.T).T f_surf_global = np.dot(fp_rot_mat, f_surf_local.T).T m_surf_global = np.dot(fp_rot_mat, m_surf_local.T).T # values for the lab output m_cop_lab = m_cop_global cop_lab = fp_cen+cop_surf_global f_cop_lab = f_surf_global # prepare return values fp_data.update({'F_SURF_LOCAL': f_surf_local}) fp_data.update({'M_SURF_LOCAL': m_surf_local}) fp_data.update({'COP_SURF_LOCAL': cop_surf_local}) fp_data.update({'F_SURF_GLOBAL': f_surf_global}) fp_data.update({'M_SURF_GLOBAL': m_surf_global}) fp_data.update({'COP_SURF_GLOBAL': cop_surf_global}) fp_data.update({'F_COP_LAB': f_cop_lab}) fp_data.update({'M_COP_LAB': m_cop_lab}) fp_data.update({'COP_LAB': cop_lab}) if fp_type == 1: fp_data.update({'COP_LOCAL_INPUT': np.stack([cop_l_x_in, cop_l_y_in, zero_vals], axis=1)}) fp_output.update({fp_idx: fp_data}) fp_idx += 1 return fp_output
def plot_emg(filename, color1, color2, report_directory, title="EMG"): reader = btk.btkAcquisitionFileReader() reader.SetFilename(filename) reader.Update() acq = reader.GetOutput() name_emg = ["VL", "Gastroc", "RF", "IJ", "TA"] time_activation = { "VL": np.array([-10, 15, 90, 115]), "Gastroc": np.array([15, 52]), "RF": np.array([55, 65]), "IJ": np.array([-10, 12, 90, 110]), "TA": np.array([-45, 10, 55, 110]) } emg_R = {} emg_L = {} for muscle_name in name_emg: emg_R[muscle_name] = acq.GetAnalog("R" + muscle_name).GetValues() emg_L[muscle_name] = acq.GetAnalog("L" + muscle_name).GetValues() # Initialisation des lists contenant les evenements L_FO = [] R_FO = [] L_FS = [] R_FS = [] for it in btk.Iterate(acq.GetEvents()): if it.GetContext().lower() == "left": if it.GetLabel() == 'Foot Strike': L_FS.append(it.GetFrame()) elif it.GetLabel() == 'Foot Off': L_FO.append(it.GetFrame()) elif it.GetContext().lower() == 'right': if it.GetLabel() == 'Foot Strike': R_FS.append(it.GetFrame()) elif it.GetLabel() == 'Foot Off': R_FO.append(it.GetFrame()) L_FO.sort() R_FO.sort() L_FS.sort() R_FS.sort() point2analog = acq.GetAnalogFrequency() / float(acq.GetPointFrequency()) # On enleve tout les evenements qui sont avant le premier foot strike du coté étudié first_frame = acq.GetFirstFrame() L_FS = [(x - first_frame) * point2analog for x in L_FS] R_FS = [(x - first_frame) * point2analog for x in R_FS] L_FO = [(x - first_frame) * point2analog for x in L_FO] R_FO = [(x - first_frame) * point2analog for x in R_FO] numbre_emg = len(name_emg) nbr_frame = np.size(acq.GetAnalog("R" + name_emg[0]).GetValues(), 0) fig, axis = plt.subplots(numbre_emg * 2, 1, figsize=(8.27, 11.69), dpi=100) for ind_muscle, muscle_name in enumerate(name_emg): ax_temp_R = axis[ind_muscle * 2] ax_temp_L = axis[ind_muscle * 2 + 1] ax_temp_R.set_ylim([-0.5, 0.5]) ax_temp_L.set_ylim([-0.5, 0.5]) ax_temp_R.plot(emg_R[muscle_name], color=color2, linewidth=1.0) ax_temp_R.set_title("R " + muscle_name, fontsize=8) ax_temp_R.set_xlim((0, nbr_frame)) ax_temp_R.set_xticklabels([]) ax_temp_L.plot(emg_L[muscle_name], color=color1) ax_temp_L.set_title("L " + muscle_name, fontsize=8) ax_temp_L.set_xlim((0, nbr_frame)) if not ind_muscle == numbre_emg: ax_temp_L.set_xticklabels([]) for axis_temp in [ax_temp_R, ax_temp_L]: for x_event in L_FS: y_lim = axis_temp.get_ylim() axis_temp.plot([x_event, x_event], y_lim, color=color1) axis_temp.set_ylim(y_lim) for x_event in L_FO: y_lim = axis_temp.get_ylim() axis_temp.plot([x_event, x_event], y_lim, color=color1, linestyle='--') axis_temp.set_ylim(y_lim) for x_event in R_FS: y_lim = axis_temp.get_ylim() axis_temp.plot([x_event, x_event], y_lim, color=color2) axis_temp.set_ylim(y_lim) for x_event in R_FO: y_lim = axis_temp.get_ylim() axis_temp.plot([x_event, x_event], y_lim, color=color2, linestyle='--') axis_temp.set_ylim(y_lim) # tracer de la norme for ind_event in range(len(L_FS) - 1): nb_frame = L_FS[ind_event + 1] - L_FS[ind_event] frame_norm_emg = nb_frame * time_activation[ muscle_name] / 100.0 + L_FS[ind_event] if ind_event == (len(L_FS) - 2): nb_activation = len(frame_norm_emg) / 2 else: nb_activation = 1 for ind_activation in range(nb_activation): ind1 = frame_norm_emg[ind_activation * 2] ind2 = frame_norm_emg[ind_activation * 2 + 1] y_lim = ax_temp_L.get_ylim() division = (y_lim[1] - y_lim[0]) / 8.0 bas_y = y_lim[0] + 7 * division ax_temp_L.add_patch( patches.Rectangle((ind1, bas_y), ind2 - ind1, division, facecolor=[0.8, 0.8, 0.8], zorder=-10)) for ind_event in range(len(R_FS) - 1): nb_frame = R_FS[ind_event + 1] - R_FS[ind_event] frame_norm_emg = nb_frame * time_activation[ muscle_name] / 100.0 + R_FS[ind_event] if ind_event == (len(R_FS) - 2): nb_activation = len(frame_norm_emg) / 2 else: nb_activation = 1 for ind_activation in range(nb_activation): ind1 = frame_norm_emg[ind_activation * 2] ind2 = frame_norm_emg[ind_activation * 2 + 1] y_lim = ax_temp_R.get_ylim() division = (y_lim[1] - y_lim[0]) / 8.0 bas_y = y_lim[0] + 7 * division ax_temp_R.add_patch( patches.Rectangle((ind1, bas_y), ind2 - ind1, division, facecolor=[0.8, 0.8, 0.8], zorder=-10)) plt.tight_layout() report_directory_final = os.path.join(report_directory, 'EMG') if not os.path.isdir(report_directory_final): os.makedirs(report_directory_final) file_name = os.path.join(report_directory_final, title + '.png') print('Sauvegarde du fichier ' + title) fig.savefig(file_name, bbox_inches='tight') plt.close(fig) file_name_final = file_name return file_name_final
def extract_kinematics(leg, filename): m = re.match(input_dir + "(?P<name>.+).c3d", filename) name = m.group('name').replace(" ", "-") output_file = "%s/%s.csv" % (output_dir, name) print("Trying %s" % (filename)) # Open c3d and read data reader = btk.btkAcquisitionFileReader() reader.SetFilename(str(filename)) reader.Update() acq = reader.GetOutput() nframes = acq.GetPointFrameNumber() start = acq.GetFirstFrame() end = acq.GetLastFrame() # Check if there is a FOG for event in btk.Iterate(acq.GetEvents()): if event.GetLabel() == 'FOG': end = event.GetFrame() nframes = end - start if os.path.isfile(output_file): return metadata = acq.GetMetaData() # We extract only kinematics kinematics = ["HipAngles", "KneeAngles", "AnkleAngles"] markers = ["TOE", "KNE", "HEE"] # ------------ Cols # If marker: # 2 * 3 * 3 = 18 kinematics # 2 * 3 * 3 = 18 marker trajectories # 2 * 3 * 3 = 18 marker trajectory derivatives # 2 * 3 * 3 = 18 kinematics derivatives # = 72 # If no markers (kin): # 2 * 3 * 3 = 18 kinematics # 2 * 3 * 3 = 18 kinematics derivatives # = 36 outputs = np.array([[0] * nframes]).T # Check if there are any kinematics in the file brk = True for point in btk.Iterate(acq.GetPoints()): if point.GetLabel() == "L" + kinematics[0]: brk = False break if brk: print("No kinematics in %s!" % (filename, )) return # Combine kinematics into one big array opposite = {'L': 'R', 'R': 'L'} angles = [None] * (len(kinematics) * 2) for i, v in enumerate(kinematics): point = acq.GetPoint(leg + v) angles[i] = point.GetValues() angles[i] = angles[i][:nframes] point = acq.GetPoint(opposite[leg] + v) angles[len(kinematics) + i] = point.GetValues() angles[len(kinematics) + i] = angles[len(kinematics) + i][:nframes] # Get the pelvis if sacr: SACR_X = acq.GetPoint("SACR").GetValues()[:, 0] else: LPSI_X = acq.GetPoint("LPSI").GetValues()[:, 0] RPSI_X = acq.GetPoint("RPSI").GetValues()[:, 0] midPSI_X = (LPSI_X + RPSI_X) / 2 SACR_X = midPSI_X # incrementX = 1 if midASI[100][0] > midASI[0][0] else -1 pos = [None] * (len(markers) * 2) pos_sacr_X = [None] * (len(markers) * 2) pos_sacr_Y = [None] * (len(markers) * 2) pos_sacr_Z = [None] * (len(markers) * 2) pos_sacr = [None] * (len(markers) * 2) for j, w in enumerate(markers): try: point = acq.GetPoint(leg + w) pos[j] = point.GetValues() pos_sacr_X[j] = point.GetValues()[:, 0] - SACR_X pos_sacr_Y[j] = point.GetValues()[:, 1] pos_sacr_Z[j] = point.GetValues()[:, 2] pos_sacr[j] = np.column_stack( (pos_sacr_X[j], pos_sacr_Y[j], pos_sacr_Z[j])) pos_sacr[j] = pos_sacr[j][:nframes] point = acq.GetPoint(opposite[leg] + w) pos[len(markers) + j] = point.GetValues() pos_sacr_X[len(markers) + j] = point.GetValues()[:, 0] - SACR_X pos_sacr_Y[len(markers) + j] = point.GetValues()[:, 1] pos_sacr_Z[len(markers) + j] = point.GetValues()[:, 2] pos_sacr[len(markers) + j] = np.column_stack( (pos_sacr_X[len(markers) + j], pos_sacr_Y[len(markers) + j], pos_sacr_Z[len(markers) + j])) pos_sacr[len(markers) + j] = pos_sacr[len(markers) + j][:nframes] except: return # Low pass filter at 7Hz angles_lp = butter_lowpass_filter(np.hstack(angles), cutoff=7, fs=100) markers_lp = butter_lowpass_filter(np.hstack(pos_sacr), cutoff=7, fs=100) # Get derivatives angles_lp_vel = derivative(angles_lp, nframes) markers_lp_vel = derivative(markers_lp, nframes) angles = np.hstack((angles_lp, angles_lp_vel)) markers = np.hstack((markers_lp, markers_lp_vel)) if marker: curves = np.concatenate((angles, markers), axis=1) else: curves = angles # Add events as output for event in btk.Iterate(acq.GetEvents()): if start < event.GetFrame() < end: if event.GetLabel() == "Foot Strike": if event.GetContext() == 'Left': outputs[event.GetFrame() - start, 0] = 1 elif event.GetContext() == 'Right': outputs[event.GetFrame() - start, 0] = 2 elif event.GetLabel() == "Foot Off": if event.GetContext() == 'Left': outputs[event.GetFrame() - start, 0] = 3 elif event.GetContext() == 'Right': outputs[event.GetFrame() - start, 0] = 4 if (np.sum(outputs) == 0): print("No events in %s!" % (filename, )) return arr = np.concatenate((curves, outputs), axis=1) # Remove data before and after first event minus some random int. This is for those trials that are not pre-cut (Spildooren). if sacr: positives = np.where(arr[:, 36] > 0.5) if len(positives[0]) == 0: return None first_event = positives[0][0] - random.randint(5, 15) last_event = positives[0][-1] + random.randint(5, 15) arr = arr[first_event:last_event] print("Writig %s" % filename) np.savetxt(output_file, arr, delimiter=',')