def __init__(self, model, **projection_params): ''' RegisteredRetinotopyModel(model, <projection parameters...>) yields a retinotopy mesh model object in which the given RetinotopyModel object model describes the 2D retinotopy that is predicted for the vertices that result from a map projection, defined using the given projection_params dictionary, of the given registration. In other words, the resulting RegisteredRetinotopyModel will, when given a hemisphere object to which to apply the model, will look up the appropriate registration (by the name registration_name) make a map projection of using the given projection_params dictionary, and apply the model to the resulting coordinates. See also neuropythy.freesurfer's Hemisphere.projection_data method for details on the projection parameters; ''' self.model = model if 'registration' not in projection_params: projection_params['registration'] = 'fsaverage_sym' if 'chirality' in projection_params: chirality = projection_params['chirality'] elif 'hemi' in projection_params: chirality = projection_params['hemi'] elif 'hemisphere' in projection_params: chirality = projection_params['hemisphere'] else: chirality = None if chirality is None: self.projection_data = nfs.Hemisphere._make_projection( **projection_params) else: sub = nfs.freesurfer_subject(projection_params['registration']) hemi = sub.LH if chirality.upper() == 'LH' else sub.RH self.projection_data = hemi.projection_data(**projection_params)
def __init__(self, model, **projection_params): ''' RegisteredRetinotopyModel(model, <projection parameters...>) yields a retinotopy mesh model object in which the given RetinotopyModel object model describes the 2D retinotopy that is predicted for the vertices that result from a map projection, defined using the given projection_params dictionary, of the given registration. In other words, the resulting RegisteredRetinotopyModel will, when given a hemisphere object to which to apply the model, will look up the appropriate registration (by the name registration_name) make a map projection of using the given projection_params dictionary, and apply the model to the resulting coordinates. See also neuropythy.freesurfer's Hemisphere.projection_data method for details on the projection parameters; ''' self.model = model if 'registration' not in projection_params: projection_params['registration'] = 'fsaverage_sym' if 'chirality' in projection_params: chirality = projection_params['chirality'] elif 'hemi' in projection_params: chirality = projection_params['hemi'] elif 'hemisphere' in projection_params: chirality = projection_params['hemisphere'] else: chirality = None if chirality is None: self.projection_data = nfs.Hemisphere._make_projection(**projection_params) else: sub = nfs.freesurfer_subject(projection_params['registration']) hemi = sub.LH if chirality.upper() == 'LH' else sub.RH self.projection_data = hemi.projection_data(**projection_params)
def benson14_retinotopy(sub): ''' benson14_retinotopy(subject) yields a pair of dictionaries each with three keys: polar_angle, eccentricity, and v123roi; each of these keys maps to a numpy array with one entry per vertex. The first element of the yielded pair is the left hemisphere map and the second is the right hemisphere map. The values are obtained by resampling the Benson et al. 2014 anatomically defined template of retinotopy to the given subject. Note that the subject must have been registered to the fsaverage_sym subject prior to calling this function; this requires using the surfreg command (after the xhemireg command for the RH). Additionally, you must have the fsaverage_sym template files in your fsaverage_syn/surf directory; these files are sym.template_angle.mgz, sym.template_eccen.mgz, and sym.template_areas.mgz. ''' global __benson14_templates if __benson14_templates is None: # Find a sym template that has the right data: sym_path = next((os.path.join(path0, 'fsaverage_sym') for path0 in subject_paths() for path in [os.path.join(path0, 'fsaverage_sym', 'surf')] if os.path.isfile(os.path.join(path, 'sym.template_angle.mgz')) \ and os.path.isfile(os.path.join(path, 'sym.template_eccen.mgz')) \ and os.path.isfile(os.path.join(path, 'sym.template_areas.mgz'))), None) if sym_path is None: raise ValueError('No fsaverage_sym subject found with surf/sym.template_*.mgz files!') sym = freesurfer_subject(sym_path).LH tmpl_path = os.path.join(sym_path, 'surf', 'sym.template_') # We need to load in the template data __benson14_templates = { 'angle': fsmgh.load(tmpl_path + 'angle.mgz').get_data().flatten(), 'eccen': fsmgh.load(tmpl_path + 'eccen.mgz').get_data().flatten(), 'v123r': fsmgh.load(tmpl_path + 'areas.mgz').get_data().flatten()} # Okay, we just need to interpolate over to this subject sym = freesurfer_subject('fsaverage_sym').LH return ( {'polar_angle': sub.LH.interpolate(sym, __benson14_templates['angle'], apply=False), 'eccentricity': sub.LH.interpolate(sym, __benson14_templates['eccen'], apply=False), 'v123roi': sub.LH.interpolate(sym, __benson14_templates['v123r'], apply=False, method='nearest')}, {'polar_angle': sub.RHX.interpolate(sym, __benson14_templates['angle'], apply=False), 'eccentricity': sub.RHX.interpolate(sym, __benson14_templates['eccen'], apply=False), 'v123roi': sub.RHX.interpolate(sym, __benson14_templates['v123r'], apply=False, method='nearest')})
def surface_to_ribbon_command(args): ''' surface_to_rubbon_command(args) can be given a list of arguments, such as sys.argv[1:]; these arguments may include any options and must include exactly one subject id and one output filename. Additionally one or two surface input filenames must be given. The surface files are projected into the ribbon and written to the output filename. For more information see the string stored in surface_to_ribbon_help. ''' # Parse the arguments (args, opts) = _surface_to_ribbon_parser(args) # First, help? if opts['help']: print surface_to_ribbon_help return 1 # and if we are verbose, lets setup a note function verbose = opts['verbose'] def note(s): if verbose: print s return verbose # Add the subjects directory, if there is one if 'subjects_dir' in opts and opts['subjects_dir'] is not None: add_subject_path(opts['subjects_dir']) # figure out our arguments: (lhfl, rhfl) = (opts['lh_file'], opts['rh_file']) if len(args) == 0: raise ValueError('Not enough arguments provided!') elif len(args) == 1: # must be that the subject is in the env? sub = find_subject_path(os.getenv('SUBJECT')) outfl = args[0] elif len(args) == 2: sbpth = find_subject_path(args[0]) if sbpth is not None: sub = sbpth else: sub = find_subject_path(os.getenv('SUBJECT')) if lhfl is not None: rhfl = args[0] elif rhfl is not None: lhfl = args[0] else: raise ValueError('Given arg is not a subject: %s' % args[0]) outfl = args[1] elif len(args) == 3: sbpth0 = find_subject_path(args[0]) sbpth1 = find_subject_path(args[1]) if sbpth0 is not None: sub = sbpth0 if lhfl is not None: rhfl = args[1] elif rhfl is not None: lhfl = args[1] else: raise ValueError('Too many arguments given: %s' % args[1]) elif sbpth1 is not None: sub = sbpth1 if lhfl is not None: rhfl = args[0] elif rhfl is not None: lhfl = args[0] else: raise ValueError('Too many arguments given: %s' % args[0]) else: sub = find_subject_path(os.getenv('SUBJECT')) if lhfl is not None or rhfl is not None: raise ValueError('Too many arguments and no subject given') (lhfl, rhfl) = args outfl = args[2] elif len(args) == 4: if lhfl is not None or rhfl is not None: raise ValueError('Too many arguments and no subject given') subidx = next((i for (i,a) in enumerate(args) if find_subject_path(a) is not None), None) if subidx is None: raise ValueError('No subject given') sub = find_subject_path(args[subidx]) del args[subidx] (lhfl, rhfl, outfl) = args else: raise ValueError('Too many arguments provided!') if sub is None: raise ValueError('No subject specified or found in $SUBJECT') if lhfl is None and rhfl is None: raise ValueError('No surfaces provided') # check the method method = opts['method'].lower() if method != 'weighted' and method != 'max': raise ValueError('Unsupported method: %s' % method) # and the datatype if opts['dtype'] is None: dtyp = None elif opts['dtype'].lower() == 'float': dtyp = np.float32 elif opts['dtype'].lower() == 'int': dtyp = np.int32 else: raise ValueError('Type argument must be float or int') # Now, load the data: note('Reading surfaces...') (lhdat, rhdat) = (None, None) if lhfl is not None: note(' - Reading LH file: %s' % lhfl) lhdat = read_surf_file(lhfl) if rhfl is not None: note(' - Reading RH file: %s' % rhfl) rhdat = read_surf_file(rhfl) (dat, hemi) = (rhdat, 'rh') if lhdat is None else \ (lhdat, 'lh') if rhdat is None else \ ((lhdat, rhdat), None) note('Generating vertex-to-voxel mapping...') sub = freesurfer_subject(sub) s2r = cortex_to_ribbon_map(sub, hemi=hemi) # okay, make the volume... note('Generating volume...') vol = cortex_to_ribbon(sub, dat, map=s2r, hemi=hemi, method=method, fill=opts['fill'], dtype=dtyp) # and write out the file note('Exporting volume file: %s' % outfl) vol.to_filename(outfl) note('surface_to_ribbon complete!') return 0
def register_retinotopy_command(args): ''' register_retinotopy_command(args) can be given a list of arguments, such as sys.argv[1:]; these arguments may include any options and must include at least one subject id. All subjects whose ids are given are registered to a retinotopy model, and the resulting registration, as well as the predictions made by the model in the registration, are exported. ''' # Parse the arguments (args, opts) = _retinotopy_parser(args) # First, help? if opts['help']: print register_retinotopy_help return 1 # and if we are verbose, lets setup a note function verbose = opts['verbose'] def note(s): if verbose: print s return verbose # Add the subjects directory, if there is one if 'subjects_dir' in opts and opts['subjects_dir'] is not None: add_subject_path(opts['subjects_dir']) # Parse the simple numbers for o in ['weight_cutoff', 'edge_strength', 'angle_strength', 'func_strength', 'max_step_size', 'max_out_eccen']: opts[o] = float(opts[o]) opts['max_steps'] = int(opts['max_steps']) # These are for now not supported: #TODO if opts['angle_math'] or opts['angle_radians'] or opts['eccen_radians']: print 'Mathematical angles and angles not in degrees are not yet supported.' return 1 # The remainder of the args can wait for now; walk through the subjects: tag_key = {'eccen': 'eccentricity', 'angle': 'polar_angle', 'label': 'V123_label'} for subnm in args: sub = freesurfer_subject(subnm) note('Processing subject: %s' % sub.id) # we need to register this subject... res = {} ow = not opts['no_overwrite'] for h in ['LH','RH']: note(' Processing hemisphere: %s' % h) hemi = sub.__getattr__(h) # See if we are loading custom values... (ang,ecc,wgt) = (None,None,None) suffix = '_' + h.lower() + '_file' if opts['angle' + suffix] is not None: ang = _guess_surf_file(opts['angle' + suffix]) if opts['eccen' + suffix] is not None: ecc = _guess_surf_file(opts['eccen' + suffix]) if opts['weight' + suffix] is not None: wgt = _guess_surf_file(opts['weight' + suffix]) # Do the registration note(' - Running Registration...') res[h] = register_retinotopy(hemi, V123_model(), polar_angle=ang, eccentricity=ecc, weight=wgt, weight_cutoff=opts['weight_cutoff'], partial_voluming_correction=opts['part_vol_correct'], edge_scale=opts['edge_strength'], angle_scale=opts['angle_strength'], functional_scale=opts['func_strength'], prior=opts['prior'], max_predicted_eccen=opts['max_out_eccen'], max_steps=opts['max_steps'], max_step_size=opts['max_step_size']) # Perform the hemi-specific outputs now: if not opts['no_reg_export']: regnm = '.'.join([h.lower(), opts['registration_name'], 'sphere', 'reg']) flnm = (os.path.join(sub.directory, 'surf', regnm) if h == 'LH' else os.path.join(sub.directory, 'xhemi', 'surf', regnm)) if ow or not os.path.exist(flnm): note(' - Exporting registration file: %s' % flnm) fsio.write_geometry(flnm, res[h].coordinates.T, res[h].faces.T, 'Created by neuropythy (github.com/noahbenson/neuropythy)') else: note(' - Skipping registration file: %s (file exists)' % flnm) if not opts['no_surf_export']: for dim in ['angle', 'eccen', 'label']: flnm = os.path.join(sub.directory, 'surf', '.'.join([h.lower(), opts[dim + '_tag'], 'mgz'])) if ow or not os.path.exist(flnm): note(' - Exporting prediction file: %s' % flnm) img = fsmgh.MGHImage( np.asarray([[res[h].prop(tag_key[dim])]], dtype=(np.int32 if dim == 'label' else np.float32)), np.eye(4)) img.to_filename(flnm) else: note(' - Skipping prediction file: %s (file exists)' % flnm) # Do the volume exports here if not opts['no_vol_export']: note(' Processing volume data...') note(' - Calculating cortex-to-ribbon mapping...') surf2rib = cortex_to_ribbon_map(sub, hemi=None) for dim in ['angle', 'eccen', 'label']: flnm = os.path.join(sub.directory, 'mri', opts[dim + '_tag'] + '.mgz') if ow or not os.path.exist(flnm): note(' - Generating volume file: %s' % flnm) vol = cortex_to_ribbon(sub, (res['LH'].prop(tag_key[dim]), res['RH'].prop(tag_key[dim])), map=surf2rib, dtype=(np.int32 if dim == 'label' else np.float32)) note(' - Exporting volume file: %s' % flnm) vol.to_filename(flnm) else: note(' - Skipping volume file: %s (file exists)' % flnm) # That is it for this subject! note(' Subject %s finished!' % sub.id) # And if we made it here, all was successful. return 0
def register_retinotopy_initialize(hemi, model='standard', polar_angle=None, eccentricity=None, weight=None, weight_cutoff=0.2, max_predicted_eccen=85, partial_voluming_correction=True, prior='retinotopy', resample='fsaverage_sym'): ''' register_retinotopy_initialize(hemi, model) yields an fsaverage_sym LH hemisphere that has been prepared for retinotopic registration with the data on the given hemisphere, hemi. The options polar_angle, eccentricity, weight, and weight_cutoff are accepted, as are the prior and resample options; all are documented in help(register_retinotopy). The return value of this function is actually a dictionary with the element 'map' giving the resulting map projection, and additional entries giving other meta-data calculated along the way. ''' # Step 1: get our properties straight prop_names = ['polar_angle', 'eccentricity', 'weight'] data = {} n = hemi.vertex_count (ang, ecc, wgt) = [ extract_retinotopy_argument(hemi, name, arg, default='empirical') for (name, arg) in [ ('polar_angle', polar_angle), ('eccentricity', eccentricity), ('weight', [weight for i in range(n)] \ if isinstance(weight, Number) or np.issubdtype(type(weight), np.float) \ else weight)]] ## we also want to make sure weight is 0 where there are none values (ang, ecc, wgt) = _retinotopy_vectors_to_float(ang, ecc, wgt, weight_cutoff=weight_cutoff) ## correct for partial voluming if necessary: if partial_voluming_correction is True: wgt *= (1.0 - np.asarray(hemi.partial_volume_factor())) ## note these in the result dictionary: data['sub_polar_angle'] = ang data['sub_eccentricity'] = ecc data['sub_weight'] = wgt # Step 2: do alignment, if required if isinstance(model, basestring): model = V123_model(model) if not isinstance(model, RegisteredRetinotopyModel): raise ValueError('model must be a RegisteredRetinotopyModel') data['model'] = model model_reg = model.projection_data['registration'] model_reg = 'fsaverage_sym' if model_reg is None else model_reg model_chirality = model.projection_data['chirality'] if model_reg == 'fsaverage_sym': useHemi = hemi if hemi.chirality == 'LH' else hemi.subject.RHX else: if model_chiraliry is not None and hemi.chirality != model_chiraliry: raise ValueError('Inverse-chirality hemisphere cannot be registered to model') useHemi = hemi ## make sure we are registered to the model space if model_reg not in useHemi.topology.registrations: raise ValueError('Hemisphere is not registered to the model registration: %s' % model_reg) data['sub_hemi'] = useHemi ## note the subject's registration to the model's registration: subreg = useHemi.topology.registrations[model_reg] ## if there's a prior, we should enforce it now: if prior is not None: if hemi.subject.id == model_reg: prior_subject = useHemi.subject prior_hemi = useHemi else: prior_subject = freesurfer_subject(model_reg) prior_hemi = prior_subject.__getattr__(useHemi.chirality) if prior not in prior_hemi.topology.registrations: raise ValueError('Prior registration %s not found in prior subject %s' \ % (prior, model_reg)) if model_reg not in prior_hemi.topology.registrations: raise ValueError('Model registratio not found in prior subject: %s' % prior_subject) prior_reg0 = prior_hemi.topology.registrations[model_reg] prior_reg1 = prior_hemi.topology.registrations[prior] addr = prior_reg0.address(subreg.coordinates) data['address_in_prior'] = addr coords = prior_reg1.unaddress(addr) else: prior_hemi = None coords = subreg.coordinates prior_reg = Registration(useHemi.topology, coords) data['prior_registration'] = prior_reg data['prior_hemisphere'] = prior_hemi # Step 3: resample, if need be (for now we always resample to fsaverage_sym) data['resample'] = resample if resample is None: tohem = useHemi toreg = prior_reg data['initial_registration'] = prior_reg for (p,v) in zip(prop_names, [useHemi.prop(p) for p in prop_names]): data['initial_' + p] = v data['unresample_function'] = lambda rr: rr else: if resample == 'fsaverage_sym': tohem = freesurfer_subject('fsaverage_sym').LH toreg = tohem.topology.registrations['fsaverage_sym'] elif resample == 'fsaverage': tohem = freesurfer_subject('fsaverage').__getattr__(model_chirality) toreg = tohem.topology.registrations['fsaverage'] else: raise ValueError('resample argument must be fsaverage, fsaverage_sym, or None') data['resample_hemisphere'] = tohem resamp_addr = toreg.address(prior_reg.coordinates) data['resample_address'] = resamp_addr data['initial_registration'] = toreg for (p,v) in zip(prop_names, _retinotopy_vectors_to_float( *[toreg.interpolate_from(prior_reg, data['sub_' + p]) for p in prop_names])): data['initial_' + p] = v data['unresample_function'] = lambda rr: Registration(useHemi.topology, rr.unaddress(resamp_addr)) data['initial_mesh'] = tohem.registration_mesh(toreg) # Step 4: make the projection proj_data = model.projection_data m = proj_data['forward_function'](data['initial_mesh']) for p in prop_names: m.prop(p, data['initial_' + p][m.vertex_labels]) data['map'] = m # Step 5: Annotate how we get back def __postproc_fn(reg): d = data.copy() d['registered_coordinates'] = reg # First, unproject the map reg_map_3dx = d['map'].unproject(reg).T reg_3dx = np.array(d['initial_registration'].coordinates, copy=True) reg_3dx[d['map'].vertex_labels] = reg_map_3dx final_reg = Registration(tohem.topology, reg_3dx) d['finished_registration'] = final_reg # Now, if need be, unresample the points: d['registration'] = d['unresample_function'](final_reg) # now convert the sub points into retinotopy points rmesh = useHemi.registration_mesh(d['registration']) pred = np.asarray( [(p,e,l) if rl > 0 and rl < 4 and e <= max_predicted_eccen else (0.0, 0.0, 0) for (p,e,l) in zip(*model.cortex_to_angle(rmesh)) for rl in [round(l)]]).T pred = (np.asarray(pred[0], dtype=np.float32), np.asarray(pred[1], dtype=np.float32), np.asarray(pred[2], dtype=np.int32)) for i in (0,1,2): pred[i].flags.writeable = False pred = make_dict({p:v for (p,v) in zip(['polar_angle', 'eccentricity', 'V123_label'], pred)}) d['prediction'] = pred rmesh.prop(pred) d['registered_mesh'] = rmesh return make_dict(d) data['postprocess_function'] = __postproc_fn return data
def benson14_retinotopy_command(*args): ''' benson14_retinotopy_command(args...) runs the benson14_retinotopy command; see benson14_retinotopy_help for mor information. ''' # Parse the arguments... (args, opts) = _benson14_parser(args) # help? if opts['help']: print benson14_retinotopy_help return 1 # verbose? verbose = opts['verbose'] def note(s): if verbose: print s return verbose # Add the subjects directory, if there is one if 'subjects_dir' in opts and opts['subjects_dir'] is not None: add_subject_path(opts['subjects_dir']) ow = not opts['no_overwrite'] nse = opts['no_surf_export'] nve = opts['no_vol_export'] tr = {'polar_angle': opts['angle_tag'], 'eccentricity': opts['eccen_tag'], 'v123roi': opts['label_tag']} # okay, now go through the subjects... for subnm in args: note('Processing subject %s:' % subnm) sub = freesurfer_subject(subnm) note(' - Interpolating template...') (lhdat, rhdat) = benson14_retinotopy(sub) # Export surfaces if nse: note(' - Skipping surface export.') else: note(' - Exporting surfaces:') for (t,dat) in lhdat.iteritems(): flnm = os.path.join(sub.directory, 'surf', 'lh.' + tr[t] + '.mgz') if ow or not os.path.exist(flnm): note(' - Exporting LH prediction file: %s' % flnm) img = fsmgh.MGHImage( np.asarray([[dat]], dtype=(np.int32 if t == 'v123roi' else np.float32)), np.eye(4)) img.to_filename(flnm) else: note(' - Not overwriting existing file: %s' % flnm) # Export volumes if nve: note(' - Skipping volume export.') else: surf2rib = cortex_to_ribbon_map(sub, hemi=None) note(' - Exporting Volumes:') for t in lhdat.keys(): flnm = os.path.join(sub.directory, 'mri', tr[t] + '.mgz') if ow or not os.path.exist(flnm): note(' - Preparing volume file: %s' % flnm) vol = cortex_to_ribbon(sub, (lhdat[t], rhdat[t]), map=surf2rib, dtype=(np.int32 if t == 'v123roi' else np.float32)) note(' - Exporting volume file: %s' % flnm) vol.to_filename(flnm) else: note(' - Not overwriting existing file: %s' % flnm) note(' Subject %s finished!' % sub.id) return 0
def benson14_retinotopy_command(*args): ''' benson14_retinotopy_command(args...) runs the benson14_retinotopy command; see benson14_retinotopy_help for mor information. ''' # Parse the arguments... (args, opts) = _benson14_parser(args) # help? if opts['help']: print benson14_retinotopy_help return 1 # verbose? verbose = opts['verbose'] def note(s): if verbose: print s return verbose # Add the subjects directory, if there is one if 'subjects_dir' in opts and opts['subjects_dir'] is not None: add_subject_path(opts['subjects_dir']) ow = not opts['no_overwrite'] nse = opts['no_surf_export'] nve = opts['no_vol_export'] tr = {'polar_angle': opts['angle_tag'], 'eccentricity': opts['eccen_tag'], 'visual_area': opts['label_tag']} # okay, now go through the subjects... for subnm in args: note('Processing subject %s:' % subnm) sub = freesurfer_subject(subnm) note(' - Interpolating template...') (lhdat, rhdat) = predict_retinotopy(sub, template=opts['template']) # Export surfaces if nse: note(' - Skipping surface export.') else: note(' - Exporting surfaces:') for (t,dat) in lhdat.iteritems(): flnm = os.path.join(sub.directory, 'surf', 'lh.' + tr[t] + '.mgz') if ow or not os.path.exist(flnm): note(' - Exporting LH prediction file: %s' % flnm) img = fsmgh.MGHImage( np.asarray([[dat]], dtype=(np.int32 if t == 'visual_area' else np.float32)), np.eye(4)) img.to_filename(flnm) else: note(' - Not overwriting existing file: %s' % flnm) for (t,dat) in rhdat.iteritems(): flnm = os.path.join(sub.directory, 'surf', 'rh.' + tr[t] + '.mgz') if ow or not os.path.exist(flnm): note(' - Exporting RH prediction file: %s' % flnm) img = fsmgh.MGHImage( np.asarray([[dat]], dtype=(np.int32 if t == 'visual_area' else np.float32)), np.eye(4)) img.to_filename(flnm) else: note(' - Not overwriting existing file: %s' % flnm) # Export volumes if nve: note(' - Skipping volume export.') else: surf2rib = cortex_to_ribbon_map(sub, hemi=None) note(' - Exporting Volumes:') for t in lhdat.keys(): flnm = os.path.join(sub.directory, 'mri', tr[t] + '.mgz') if ow or not os.path.exist(flnm): note(' - Preparing volume file: %s' % flnm) vol = cortex_to_ribbon(sub, (lhdat[t], rhdat[t]), map=surf2rib, method=('max' if t == 'visual_area' else 'weighted'), dtype=(np.int32 if t == 'visual_area' else np.float32)) note(' - Exporting volume file: %s' % flnm) vol.to_filename(flnm) else: note(' - Not overwriting existing file: %s' % flnm) note(' Subject %s finished!' % sub.id) return 0
def register_retinotopy_command(args): ''' register_retinotopy_command(args) can be given a list of arguments, such as sys.argv[1:]; these arguments may include any options and must include at least one subject id. All subjects whose ids are given are registered to a retinotopy model, and the resulting registration, as well as the predictions made by the model in the registration, are exported. ''' # Parse the arguments (args, opts) = _retinotopy_parser(args) # First, help? if opts['help']: print register_retinotopy_help return 1 # and if we are verbose, lets setup a note function verbose = opts['verbose'] def note(s): if verbose: print s return verbose # Add the subjects directory, if there is one if 'subjects_dir' in opts and opts['subjects_dir'] is not None: add_subject_path(opts['subjects_dir']) # Parse the simple numbers for o in [ 'weight_cutoff', 'edge_strength', 'angle_strength', 'func_strength', 'max_step_size', 'max_out_eccen' ]: opts[o] = float(opts[o]) opts['max_steps'] = int(opts['max_steps']) # These are for now not supported: #TODO if opts['angle_math'] or opts['angle_radians'] or opts['eccen_radians']: print 'Mathematical angles and angles not in degrees are not yet supported.' return 1 # The remainder of the args can wait for now; walk through the subjects: tag_key = { 'eccen': 'eccentricity', 'angle': 'polar_angle', 'label': 'visual_area' } for subnm in args: sub = freesurfer_subject(subnm) note('Processing subject: %s' % sub.id) # we need to register this subject... res = {} ow = not opts['no_overwrite'] for h in ['LH', 'RH']: note(' Processing hemisphere: %s' % h) hemi = sub.__getattr__(h) # See if we are loading custom values... (ang, ecc, wgt) = (None, None, None) suffix = '_' + h.lower() + '_file' if opts['angle' + suffix] is not None: ang = _guess_surf_file(opts['angle' + suffix]) if opts['eccen' + suffix] is not None: ecc = _guess_surf_file(opts['eccen' + suffix]) if opts['weight' + suffix] is not None: wgt = _guess_surf_file(opts['weight' + suffix]) # Do the registration note(' - Running Registration...') res[h] = register_retinotopy( hemi, retinotopy_model(), polar_angle=ang, eccentricity=ecc, weight=wgt, weight_cutoff=opts['weight_cutoff'], partial_voluming_correction=opts['part_vol_correct'], edge_scale=opts['edge_strength'], angle_scale=opts['angle_strength'], functional_scale=opts['func_strength'], prior=opts['prior'], max_predicted_eccen=opts['max_out_eccen'], max_steps=opts['max_steps'], max_step_size=opts['max_step_size']) # Perform the hemi-specific outputs now: if not opts['no_reg_export']: regnm = '.'.join( [h.lower(), opts['registration_name'], 'sphere', 'reg']) flnm = (os.path.join(sub.directory, 'surf', regnm) if h == 'LH' else os.path.join(sub.directory, 'xhemi', 'surf', regnm)) if ow or not os.path.exist(flnm): note(' - Exporting registration file: %s' % flnm) fsio.write_geometry( flnm, res[h].coordinates.T, res[h].faces.T, 'Created by neuropythy (github.com/noahbenson/neuropythy)' ) else: note(' - Skipping registration file: %s (file exists)' % flnm) if not opts['no_surf_export']: for dim in ['angle', 'eccen', 'label']: flnm = os.path.join( sub.directory, 'surf', '.'.join([h.lower(), opts[dim + '_tag'], 'mgz'])) if ow or not os.path.exist(flnm): note(' - Exporting prediction file: %s' % flnm) img = fsmgh.MGHImage( np.asarray([[res[h].prop(tag_key[dim])]], dtype=(np.int32 if dim == 'label' else np.float32)), np.eye(4)) img.to_filename(flnm) else: note(' - Skipping prediction file: %s (file exists)' % flnm) # Do the volume exports here if not opts['no_vol_export']: note(' Processing volume data...') note(' - Calculating cortex-to-ribbon mapping...') surf2rib = cortex_to_ribbon_map(sub, hemi=None) for dim in ['angle', 'eccen', 'label']: flnm = os.path.join(sub.directory, 'mri', opts[dim + '_tag'] + '.mgz') if ow or not os.path.exist(flnm): note(' - Generating volume file: %s' % flnm) vol = cortex_to_ribbon( sub, (res['LH'].prop(tag_key[dim]), res['RH'].prop( tag_key[dim])), map=surf2rib, method=('max' if dim == 'label' else 'weighted'), dtype=(np.int32 if dim == 'label' else np.float32)) note(' - Exporting volume file: %s' % flnm) vol.to_filename(flnm) else: note(' - Skipping volume file: %s (file exists)' % flnm) # That is it for this subject! note(' Subject %s finished!' % sub.id) # And if we made it here, all was successful. return 0