Esempio n. 1
0
 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)
Esempio n. 2
0
 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)
Esempio n. 3
0
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')})
Esempio n. 4
0
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    
Esempio n. 6
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