def create_trans(subject, db_fs, db_bv, fname_out): """ Get transformations of the surface from a file that containes filename matrix transformations """ trans_list = [] trans_name = [ op.join(db_fs, '{0}/mri/transforms/{0}_orig_TO_meshes.trm'), 'inv ' + op.join(db_fs, '{0}/mri/transforms/orig_{0}_TO_Scanner_Based.trm'), op.join( db_bv, '{0}/t1mri/default_acquisition/registration/RawT1-{0}_default_acquisition_TO_Scanner_Based.trm' ) ] for name in trans_name: split = name.split() inv_bool = ('inv' == split[0]) if inv_bool: name = split[1] else: name = split[0] print(name) format_name = name.format(subject) print(format_name) # if not os.path.exists(format_name): # print("error, {} is not an existing path, will try to add \ # subject_dir {}".format(format_name, database)) # # format_name = os.path.join(database, format_name) # print(format_name) # assert os.path.exists(format_name), "Breaking, even when add \ # subject_dir, file {} do not exists".format(name) with open(format_name, 'r') as matfile: lines = matfile.read().strip().split("\n") lines_list = [l.split() for l in lines] translation = lines_list.pop(0) # transpose the rotations transpose = list(zip(*lines_list)) # append translations transpose.append(translation) # create the matrix mat_str = np.array(list(zip(*transpose))) mat = mat_str.astype(np.float) mat = np.vstack([mat, [0, 0, 0, 1]]) if inv_bool: mat = inv(mat) # add line por computing translation trans_list.append(mat) trans = None for trans_cour in trans_list: if trans is None: trans = trans_cour else: trans = np.dot(trans, trans_cour) if fname_out.endswith('fif'): write_trans(fname_out, trans) else: with open(fname_out, 'w') as matfile: # un autre nom semblerait judiceiux pour eviter la confuction # avec le matfile de la partie precedente de la fonction for i in range(len(trans)): for j in range(len(trans[i])): matfile.write(str(trans[i][j]) + ' ') matfile.write('\n') return trans
def create_trans(subject, fname, fname_out): """ Get transformations of the surface from a file that containes filename matrix transformations """ trans_list = [] with open(fname, 'r') as textfile: trans_name = textfile.read().strip().split("\n") for name in trans_name: split = name.split() inv_bool = ('inv' == split[0]) if inv_bool: name = split[1] else: name = split[0] name = name.format(subject) with open(name, 'r') as matfile: lines = matfile.read().strip().split("\n") lines_list = [l.split() for l in lines] translation = lines_list.pop(0) #transpose the rotations transpose = list(zip(*lines_list)) #append translations transpose.append(translation) #create the matrix mat_str = np.array(list(zip(*transpose))) #mat_str= np.array(lines_list) mat = mat_str.astype(np.float) mat = np.vstack([mat, [0, 0, 0, 1]]) if inv_bool: mat = inv(mat) #add line por computing translation trans_list.append(mat) res = None trans = None for trans_cour in trans_list: if trans is None: trans = trans_cour else: trans = np.dot(trans, trans_cour) if fname_out.endswith('fif'): write_trans(fname_out, trans) else: with open(fname_out, 'w') as matfile: for i in range(len(trans)): for j in range(len(trans[i])): matfile.write(str(trans[i][j]) + ' ') matfile.write('\n') return trans
def create_trans(subject, fname, fname_out): """ Get transformations of the surface from a file that containes filename matrix transformations """ trans_list = [] with open(fname, 'r') as textfile: trans_name = textfile.read().strip().split('\n') for name in trans_name: split = name.split() inv_bool = ('inv' == split[0]) if inv_bool: name = split[1] else: name = split[0] name = name.format(subject) with open(name, 'r') as matfile: lines = matfile.read().strip().split('\r') lines_list = [l.split() for l in lines] translation = lines_list.pop(0) # transpose the rotations transpose = list(zip(*lines_list)) # append translations transpose.append(translation) # create the matrix mat_str = np.array(list(zip(*transpose))) mat = mat_str.astype(np.float) mat = np.reshape(mat, (3, 4), order='F') mat = np.vstack([mat, [1, 0, 0, 0]]) mat = np.transpose(mat) mat = np.rot90(mat, 3) # Neer to rotate if inv_bool: mat = inv(mat) # add line por computing translation trans_list.append(mat) res = None trans = None # Why do we need the next loop? for trans_cour in trans_list: if trans is None: trans = trans_cour else: trans = np.dot(trans, trans_cour) if fname_out.endswith('fif'): # Create Transform class X = mne.Transform(1, 2, trans) write_trans(fname_out, X) else: with open(fname_out, 'w') as matfile: for i in range(len(trans)): for j in range(len(trans[i])): matfile.write(str(trans[i][j]) + ' ') matfile.write('\n') return trans
def contAvg_headpos(condition, method='median', folder=[], summary=False): """ Calculate average transformation from dewar to head coordinates, based on the continous head position estimated from MaxFilter Parameters ---------- condition : str String containing part of common filename, e.g. "task" for files task-1.fif, task-2.fif, etc. Consistent naiming of files is mandatory! method : str How to calculate "average, "mean" or "median" (default = "median") folder : str Path to input files. Default = current dir. Returns ------- MNE-Python transform object 4x4 transformation matrix """ # Check that the method works method = method.lower() if method not in ['median', 'mean']: raise RuntimeError( 'Wrong method. Must be either \"mean\" or "median"!') if not condition: raise RuntimeError('You must provide a conditon!') # Get and set folders if not folder: rawdir = getcwd() # [!] Match up with bash script ! else: rawdir = folder print(rawdir) quatdir = op.join(rawdir, 'quat_files') mean_trans_folder = op.join(rawdir, 'trans_files') if not op.exists(mean_trans_folder): # Make sure output folder exists mkdir(mean_trans_folder) mean_trans_file = op.join(mean_trans_folder, condition + '-trans.fif') if op.isfile(mean_trans_file): warnings.warn( 'N"%s\" already exists is %s. Delete if you want to rerun' % (mean_trans_file, mean_trans_folder), RuntimeWarning) return # Change to subject dir files2combine = find_condition_files(quatdir, condition) files2combine.sort() if not files2combine: raise RuntimeError('No files called \"%s\" found in %s' % (condition, quatdir)) allfiles = [] for ff in files2combine: fl = ff.split('_')[0] tmplist = [f for f in listdir(quatdir) if fl in f and '_quat' in f] #Fix order if len(tmplist) > 1: tmplist.sort() if any("-" in f for f in tmplist): firstfile = tmplist[ -1] # The file without a number will always be last! tmpfs = sorted(tmplist[:-1], key=lambda a: int(re.split('-|.fif', a)[-2]) ) # Assuming consistent naming!!! tmplist[0] = firstfile tmplist[1:] = tmpfs allfiles = allfiles + tmplist if len(allfiles) > 1: print('Files used for average head pos:') for ib in range(len(allfiles)): print('{:d}: {:s}'.format(ib + 1, allfiles[ib])) else: print('Will find average head pos in %s' % files2combine) # LOAD DATA # raw = read_raw_fif(op.join(quatdir,firstfile), preload=True, allow_maxshield=True, verbose=False).pick_types(meg=False, chpi=True) # Use files2combine instead of allfiles as MNE will find split files automatically. for idx, ffs in enumerate(files2combine): if idx == 0: raw = read_raw_fif(op.join(quatdir, ffs), preload=True, allow_maxshield=True).pick_types(meg=False, chpi=True) else: raw.append( read_raw_fif(op.join(quatdir, ffs), preload=True, allow_maxshield=True).pick_types(meg=False, chpi=True)) quat, times = raw.get_data(return_times=True) gof = quat[6, ] # Godness of fit channel # fs = raw.info['sfreq'] # In case "record raw" started before "cHPI" if np.any(gof < 0.98): begsam = np.argmax(gof > 0.98) raw.crop(tmin=raw.times[begsam]) quat = quat[:, begsam:].copy() times = times[begsam:].copy() # Make summaries if summary: plot_movement(quat, times, dirname=rawdir, identifier=condition) total_dist_moved(quat, times, write=True, dirname=rawdir, identifier=condition) # Get continous transformation print('Reading transformation. This will take a while...') H = np.empty([4, 4, len(times)]) # Initiate transforms init_rot_angles = np.empty([len(times), 3]) for i, t in enumerate(times): Hi = np.eye(4, 4) Hi[0:3, 3] = quat[3:6, i].copy() Hi[:3, :3] = quat_to_rot(quat[0:3, i]) init_rot_angles[i, :] = rotation_angles(Hi[:3, :3]) assert (np.sum(Hi[-1]) == 1.0) # sanity check result H[:, :, i] = Hi.copy() if method in ["mean"]: H_mean = np.mean(H, axis=2) # stack, then average over new dim mean_rot_xfm = rotation3d(*tuple( np.mean(init_rot_angles, axis=0))) # stack, then average, then make new xfm elif method in ["median"]: H_mean = np.median(H, axis=2) # stack, then average over new dim mean_rot_xfm = rotation3d(*tuple( np.median(init_rot_angles, axis=0))) # stack, then average, then make new xfm H_mean[:3, :3] = mean_rot_xfm assert (np.sum(H_mean[-1]) == 1.0) # sanity check result # Create the mean structure and save as .fif mean_trans = raw.info['dev_head_t'] # use the last info as a template mean_trans['trans'] = H_mean.copy() # Write file write_trans(mean_trans_file, mean_trans) print("Wrote " + mean_trans_file) return mean_trans
def initAvg_headpos(condition=[], folder=[]): """ Write the average head position based of the initial fit of several independent files and save to a trans fif file Parameters ---------- condition : str String containing part of common filename, e.g. "task" for files task_a.fif, task_b.fif, etc. Consistent naiming of files is mandatory! If no condition is provided, it will average all files in folder. folder : str Path to input files. Default = current dir. Returns ------- None """ if not folder: rawdir = getcwd() else: rawdir = folder # Change to subject dir if not condition: files2combine = listdir(rawdir) print('Using all files in %s' % rawdir) else: files2combine = glob.glob('%s*' % condition) if not files2combine: print('No files called \"%s\" found in %s' % (condition, rawdir)) return elif len(files2combine) < 2: warnings.warn( 'Only one file, please check!', RuntimeWarning) # [!!!] should it just copy the initial headpos? # Define output mean_trans_folder = path.join(rawdir, 'trans_files') if not path.exists(mean_trans_folder): mkdir(mean_trans_folder) mean_trans_file = path.join(mean_trans_folder, condition + '-trans.fif') if op.isfile(mean_trans_file): warnings.warn( 'N"%s\" already exists is %s. Delete if you want to rerun' % (mean_trans_file, mean_trans_folder), RuntimeWarning) return files2combine = [f for f in files2combine if '.fif' in f] # Make sure only fif files files2combine.sort() print('Files used for average head pos:') for ib in range(len(files2combine)): print('{:d}: {:s}'.format(ib + 1, files2combine[ib])) init_xfm = [] init_rot = [] for ff in files2combine: fname = path.join(rawdir, ff) # first file is enough NOT ANYMORE! with warnings.catch_warnings( ): # suppress some annoying warnings for now warnings.simplefilter("ignore") info = Raw(fname, preload=False, verbose=False, allow_maxshield=True).info print( 'Ignore the warning above. We\'ll run MaxFilter in a few moments...' ) init_xfm += [info['dev_head_t']['trans']] # translations: info['dev_head_t']['trans'][:, 3][:-1] init_rot += [info['dev_head_t']['trans'][:3, :3]] mean_init_xfm = np.mean(np.stack(init_xfm), axis=0) # stack, then average over new dim init_rot_angles = [rotation_angles(m) for m in init_rot] mean_init_rot_xfm = rotation3d(*tuple( np.mean(np.stack(init_rot_angles), axis=0))) # stack, then average, then make new xfm assert (np.sum(mean_init_xfm[-1]) == 1.0) # sanity check result mean_trans = info['dev_head_t'] # use the last info as a template mean_trans['trans'] = mean_init_xfm # replace the transformation mean_trans[ 'trans'][:3, :3] = mean_init_rot_xfm # replace the rotation part mean_init_headpos = mean_trans['trans'][:-1, -1] # meters print('Mean head position (device coords): ({:.1f}, {:.1f}, {:.1f}) mm'.\ format(*tuple(mean_init_headpos*1e3))) print('Discrepancies from mean:') for ib, xfm in enumerate(init_xfm): diff = 1e3 * (xfm[:-1, -1] - mean_init_headpos) rmsdiff = np.linalg.norm(diff) print('\tSession {:d}: norm {:.1f} mm ({:.1f}, {:.1f}, {:.1f}) mm '.\ format(ib + 1, rmsdiff, *tuple(diff))) mean_rots = rotation_angles( mean_trans['trans'][:3, :3]) # these are in radians mean_rots_deg = tuple([180. * rot / np.pi for rot in mean_rots]) # convert to deg print('Mean head rotations (around x, y & z axes): ({:.1f}, {:.1f}, {:.1f}) deg'.\ format(*mean_rots_deg)) print('Block discrepancies from mean:') for ib, rot in enumerate(init_rot): cur_rots = rotation_angles(rot) diff = tuple([ 180. * cr / np.pi - mr for cr, mr in zip(cur_rots, mean_rots_deg) ]) print('\tSession {:d}: ({:.1f}, {:.1f}, {:.1f}) deg '.\ format(ib + 1, *tuple(diff))) # Write trans file write_trans(mean_trans_file, mean_trans) print("Wrote " + mean_trans_file)
def contAvg_headpos(condition, method='median', folder=[]): """ Calculate average transformation from dewar to head coordinates, based on the continous head position estimated from MaxFilter Parameters ---------- condition : str String containing part of common filename, e.g. "task" for files task-1.fif, task-2.fif, etc. Consistent naiming of files is mandatory! method : str How to calculate "average, "mean" or "median" (default = "median") folder : str Path to input files. Default = current dir. Returns ------- MNE-Python transform object 4x4 transformation matrix """ # Check that the method works if method not in ['median', 'mean']: raise RuntimeError( 'Wrong method. Must be either \"mean\" or "median"!') if not condition: raise RuntimeError('You must provide a conditon!') # Get and set folders if not folder: rawdir = getcwd() # [!] Match up with bash script ! else: rawdir = folder print(rawdir) quatdir = op.join(rawdir, 'quat_files') mean_trans_folder = op.join(rawdir, 'trans_files') if not op.exists(mean_trans_folder): # Make sure output folder exists mkdir(mean_trans_folder) mean_trans_file = op.join(mean_trans_folder, condition + '-trans.fif') if op.isfile(mean_trans_file): raise RuntimeError( 'N"%s\" already exists is %s. Delete aif you want to rerun' % (mean_trans_file, mean_trans_folder)) # Change to subject dir # files2combine = glob.glob('%s*' % condition) files2combine = [ f for f in listdir(quatdir) if condition in f and '_quat' in f ] if not files2combine: raise RuntimeError('No files called \"%s\" found in %s' % (condition, quatdir)) elif len(files2combine) > 1: print('Files used for average head pos:') for ib in range(len(files2combine)): print('{:d}: {:s}'.format(ib + 1, files2combine[ib])) else: print('Will find average head pos in %s' % files2combine) # LOAD DATA for idx, ffs in enumerate(files2combine): # print op.join(quatdir,ffs) if idx == 0: raw = read_raw_fif(op.join(quatdir, ffs), preload=True, allow_maxshield=True).pick_types(meg=False, chpi=True) else: raw.append( read_raw_fif(op.join(quatdir, ffs), preload=True, allow_maxshield=True).pick_types(meg=False, chpi=True)) quat, times = raw.get_data(return_times=True) gof = quat[6, ] # Godness of fit channel fs = raw.info['sfreq'] # In case "record raw" started before "cHPI" if np.any(gof < 0.98): begsam = np.argmax(gof > 0.98) raw.crop(tmin=raw.times[begsam]) quat = quat[:, begsam:].copy() times = times[begsam:].copy() # Get continous transformation print('Reading transformation. This will take a while...') H = np.empty([4, 4, len(times)]) # Initiate transforms init_rot_angles = np.empty([len(times), 3]) for i, t in enumerate(times): Hi = np.eye(4, 4) Hi[0:3, 3] = quat[3:6, i].copy() Hi[:3, :3] = quat_to_rot(quat[0:3, i]) init_rot_angles[i, :] = rotation_angles(Hi[:3, :3]) assert (np.sum(Hi[-1]) == 1.0) # sanity check result H[:, :, i] = Hi.copy() if method in ["mean"]: H_mean = np.mean(H, axis=2) # stack, then average over new dim mean_rot_xfm = rotation3d(*tuple( np.mean(init_rot_angles, axis=0))) # stack, then average, then make new xfm elif method in ["median"]: H_mean = np.median(H, axis=2) # stack, then average over new dim mean_rot_xfm = rotation3d(*tuple( np.median(init_rot_angles, axis=0))) # stack, then average, then make new xfm H_mean[:3, :3] = mean_rot_xfm assert (np.sum(H_mean[-1]) == 1.0) # sanity check result # Create the mean structure and save as .fif mean_trans = raw.info['dev_head_t'] # use the last info as a template mean_trans['trans'] = H_mean.copy() # plot_alignment(raw.info,subject='0406',subjects_dir='/home/mikkel/PD_motor/fs_subjects_dir/',dig=True, meg='helmet') # Write file write_trans(mean_trans_file, mean_trans) print("Wrote " + mean_trans_file) return mean_trans
if len(sys.argv) != 3: print("usage: {} subject $ds".format(sys.argv[0])) sys.exit(1) subject = sys.argv[1] dsname = sys.argv[2] try: FShome = os.environ['FREESURFER_HOME'] except KeyError: print("You must set the FREESURFER_HOME environment variable!") sys.exit(1) try: Subjdir = os.environ['SUBJECTS_DIR'] except KeyError: Subjdir = op.join(FShome, "subjects") print("Note: Using the default SUBJECTS_DIR:", Subjdir) name = op.join(Subjdir, subject, "bem", "{}-fiducials.fif".format(subject)) fids = read_fiducials(name) fidc = _fiducial_coords(fids[0]) raw = read_raw_ctf(dsname, clean_names = True, preload = False) fidd = _fiducial_coords(raw.info['dig']) xform = fit_matched_points(fidd, fidc, weights = [1, 10, 1]) t = Transform(FIFF.FIFFV_COORD_HEAD, FIFF.FIFFV_COORD_MRI, xform) name = op.join(Subjdir, subject, "bem", "{}-trans.fif".format(subject)) write_trans(name, t)