def run_alignment(config, env): '''Aligns anat (which is assumed to be aligned with EPI data) to FreeSurfer SurfVol This function strips the anatomicals (by default), then uses align_epi_anat.py to estimate the alignment, then applies this transformation to the non-skull-stripped SurfVol and also to the surfaces. Some alignment headers will be nuked''' overwrite = config['overwrite'] alignsuffix = config['al2expsuffix'] refdir = config['refdir'] fullext = config['outvol_fullext'] ext = config['outvol_ext'] if config['sid'] is None: raise ValueError('Need sid') cmds = [] if not os.path.exists(config['refdir']): cmds.append('mkdir %(refdir)s' % config) # two volumes may have to be stripped: the inpput anatomical, and the surfvol. # put them in a list here and process them similarly surfvol = '%(refdir)s/%(sid)s_SurfVol%(outvol_fullext)s' % config surfvol_ss = '%(refdir)s/%(sid)s_SurfVol%(sssuffix)s%(outvol_fullext)s' % config e_p, e_n, _, _ = utils.afni_fileparts(config['expvol']) if config['expvol_ss']: e_n = '%s%s' % (e_n, config['sssuffix']) expvol = '%s/%s%s' % (refdir, e_n, fullext) volsin = [surfvol_ss, expvol] for volin in volsin: if not os.path.exists(volin): raise ValueError('File %s does not exist' % volin) a_n = utils.afni_fileparts(volsin[0])[1] # surfvol input root name ssalprefix = '%s%s' % (a_n, alignsuffix) unity = "1 0 0 0 0 1 0 0 0 0 1 0" # we all like unity, don't we? fullmatrixfn = '%s_mat.aff12.1D' % ssalprefix aloutfns = ['%s%s' % (ssalprefix, fullext), fullmatrixfn] # expected output files if alignment worked if config['overwrite'] or not all([os.path.exists('%s/%s' % (refdir, f)) for f in aloutfns]): alignedfn = '%s/%s%s' % (refdir, ssalprefix, fullext) if config['identity']: fullmatrix_content = '"MATRIX(%s)"' % unity.replace(" ", ",") cmd = 'cd "%s"; cat_matvec %s > %s; 3dcopy -overwrite %s%s %s%s%s' % (refdir, fullmatrix_content, fullmatrixfn, a_n, ext, a_n, alignsuffix, ext) else: # use different inputs depending on whether expvol is EPI or ANAT twovolpat = ('-anat %s -epi %s -anat2epi -epi_base 0 -anat_has_skull no -epi_strip None' if config['isepi'] else '-dset1 %s -dset2 %s -dset1to2 -dset1_strip None -dset2_strip None') # use this pattern to generate a suffix twovolsuffix = twovolpat % (volsin[0], volsin[1]) aea_opts = config['aea_opts'] if config['template']: aea_opts += " -Allineate_opts '-maxrot 10 -maxshf 10 -maxscl 1.5'" # align_epi_anat.py cmd = 'cd "%s"; align_epi_anat.py -overwrite -suffix %s %s %s' % (refdir, alignsuffix, twovolsuffix, aea_opts) cmds.append(cmd) cmds.append(_set_vol_space_cmd(alignedfn, config)) utils.run_cmds(cmds, env) else: print "Alignment already done - skipping" # run these commands first, then check if everything worked properly cmds = [] # see if the expected transformation file was found if not config['identity'] and not os.path.exists('%s/%s' % (refdir, fullmatrixfn)): raise Exception("Could not find %s in %s" % (fullmatrixfn, refdir)) # now make a 3x4 matrix matrixfn = '%s%s.A2E.1D' % (a_n, alignsuffix) if overwrite or not os.path.exists('%s/%s' % (refdir, matrixfn)): cmds.append('cd "%s"; cat_matvec %s > %s || exit 1' % (refdir, fullmatrixfn, matrixfn)) # make an aligned, non-skullstripped version of SurfVol in refdir alprefix = '%s_SurfVol%s' % (config['sid'], alignsuffix) svalignedfn = '%s/%s%s' % (refdir, alprefix, fullext) newgrid = 1 # size of anatomical grid in mm. We'll have to resample, otherwise 3dWarp does # not respect the corners of the volume (as of April 2012) if overwrite or not os.path.exists(svalignedfn): #if not config['fs_sid']: # raise ValueError("Don't have a freesurfer subject id - cannot continue") #surfvolfn = '%s/%s_SurfVol+orig' % (config['sumadir'], config['fs_sid']) surfvolfn = '%s/T1.nii' % config['sumadir'] cmds.append('cd "%s";3dWarp -overwrite -newgrid %f -matvec_out2in `cat_matvec -MATRIX %s` -prefix ./%s %s' % (refdir, newgrid, matrixfn, alprefix, surfvolfn)) cmds.append(_set_vol_space_cmd('%s/%s+orig' % (refdir, alprefix), config)) else: print '%s already exists - skipping Warp' % svalignedfn utils.run_cmds(cmds, env) cmds = [] # nuke afni headers headernukefns = ['%s%s' % (f, fullext) for f in [ssalprefix, alprefix]] headernukefields = ['ALLINEATE_MATVEC_B2S_000000', 'ALLINEATE_MATVEC_S2B_000000', 'WARPDRIVE_MATVEC_FOR_000000', 'WARPDRIVE_MATVEC_INV_000000'] for fn in headernukefns: for field in headernukefields: # nuke transformation - otherwise AFNI does this unwanted transformation for us fullfn = '%s/%s' % (refdir, fn) if not (os.path.exists(fullfn) or config['identity']): raise ValueError("File %r does not exist" % fullfn) refitcmd = "3drefit -atrfloat %s '%s' %s" % (field, unity, fn) # only refit if not already in AFNI history (which is stored in HEADfile) cmd = 'cd "%s"; m=`grep "%s" %s | wc -w`; if [ $m -eq 0 ]; then %s; else echo "File %s seems already 3drefitted"; fi' % (refdir, refitcmd, fn, refitcmd, fn) cmds.append(cmd) utils.run_cmds('; '.join(cmds), env) cmds = [] # run AddEdge so that volumes can be inspected visually for alignment if config['AddEdge']: use_ss = config['expvol_ss'] # ae_{e,s}_n are AddEdge names for expvol and surfvol ae_e_n = utils.afni_fileparts(config['expvol'])[1] if use_ss: ae_e_n += config['sssuffix'] ae_s_n = ssalprefix #if use_ss else alprefix # *_ne have the output extension as well ae_e_ne = ae_e_n + ext ae_s_ne = ae_s_n + ext addedge_fns = ['%s/_ae.ExamineList.log' % refdir] exts = ['HEAD', 'BRIK'] orig_ext = '+orig' addedge_rootfns = ['%s_%s%%s' % (ae_e_n, postfix) for postfix in ['e3', 'ec', ae_s_n + '_ec']] addedge_rootfns.extend(['%s_%s%%s' % (ae_s_n, postfix) for postfix in ['e3', 'ec']]) addedge_fns_pat = ['%s.%s' % (fn, e) for fn in addedge_rootfns for e in exts] addegde_pathfns_orig = map(lambda x:os.path.join(refdir, x % '+orig'), addedge_fns_pat) + addedge_fns addegde_pathfns_ext = map(lambda x:os.path.join(refdir, x % ext), addedge_fns_pat) addegde_exists = map(os.path.exists, addegde_pathfns_ext) if overwrite or not all(addegde_exists): ae_ns = (ae_e_n, ae_s_n) cmds.extend(map(lambda fn : 'if [ -e "%s" ]; then rm "%s"; fi' % (fn, fn), addegde_pathfns_orig + addegde_pathfns_ext)) cmds.append(';'.join(['cd %s' % refdir] + [_convert_vol_space_to_orig_cmd('%s/%s%s' % (refdir, n, ext)) for n in ae_ns] + ['\@AddEdge %s+orig %s+orig' % ae_ns])) set_space_fns = addegde_pathfns_orig + ['%s/%s%s.%s' % (refdir, fn, orig_ext, exts[0]) for fn in ae_ns] for fn in set_space_fns: #['%s/%s' % (refdir, fn % orig_ext) for fn in addedge_fns_pat]: if fn.endswith('.log'): continue cmds.append('if [ -e %s ]; then %s; fi' % (fn, _set_vol_space_cmd(fn, config))) utils.run_cmds(cmds, env) cmds = [] else: print "AddEdge seems to have been run already" sid = config['sid'] plot_slice_fns = [(ae_e_n + '_e3', ae_s_n + '_e3', '%s_qa_e3.png' % sid), (None, ae_e_n + '_' + ae_s_n + '_ec', '%s_qa_ec.png' % sid)] plot_slice_imgfns = ['%s/%s' % (refdir, fn) for fn in plot_slice_fns] if overwrite or not all(map(os.path.exists, plot_slice_imgfns)): slice_dims = [0, 1, 2] slice_pos = [.35, .45, .55, .65] for fns in plot_slice_fns: input_fns = [] for i, fn in enumerate(fns): if fn is not None: fn = '%s/%s' % (refdir, fn) if i <= 1: fn += ext input_fns.append(fn) fn1, fn2, fnout = input_fns if not os.path.exists(fnout): _make_slice_plot(fn1, fn2, fnout) print "QA Image saved to %s" % fnout else: print "Already exists: %s" % fnout else: print "QA images already exist" # because AFNI uses RAI orientation but FreeSurfer LPI, make a new # affine transformation matrix in which the signs of # x and y coordinates are negated before and after the transformation matrixfn_LPI2RAI = '%s.A2E_LPI.1D' % ssalprefix if overwrite or not os.path.exists('%s/%s' % (refdir, matrixfn_LPI2RAI)): lpirai = '"MATRIX(-1,0,0,0,0,-1,0,0,0,0,1,0)"' cmd = ('cd %s; cat_matvec -ONELINE %s `cat_matvec -MATRIX %s` %s > %s' % (refdir, lpirai, matrixfn, lpirai, matrixfn_LPI2RAI)) cmds.append(cmd) # apply transformation to surfaces [icolds, hemis] = _get_hemis_icolds(config) sumadir = config['sumadir'] sumafiles = os.listdir(sumadir) origext = '.asc' ext = format2extension(config) tp = format2type(config) # process all hemispheres and ld values for icold in icolds: for hemi in hemis: pat = '%s%sh.?*%s' % (config['mi_icopat'] % icold, hemi, origext) for sumafile in sumafiles: if fnmatch.fnmatch(sumafile, pat): if not sumafile.endswith(origext): raise ValueError("%s does not end with %s" % (sumafile, origext)) #s = sumafile.split(".") #s[len(s) - 2] += config['alsuffix'] # insert '_al' just before last dot #alsumafile = ".".join(s) extsumafile = sumafile[:-len(origext)] alsumafile = extsumafile + config['alsuffix'] + ext if config['overwrite'] or not os.path.exists('%s/%s' % (refdir, alsumafile)): # now apply transformation cmd = 'cd "%s";ConvertSurface -overwrite -i_fs %s/%s -o_%s ./%s -ixmat_1D %s' % \ (refdir, sumadir, sumafile, tp, alsumafile, matrixfn_LPI2RAI) cmds.append(cmd) # as of June 2012 copy the original sphere.reg (not aligned) as well if sumafile == ('%s.sphere.reg%s' % (pat, ext)): sumaout = '%s/%s' % (refdir, extsumafile + ext) if config['overwrite'] or not os.path.exists(sumaout): s = surf.read('%s/%s' % (sumadir, sumafile)) surf.write(s, sumaout) #cmds.append('cp %s/%s %s/%s' % (sumadir, sumafile, refdir, sumafile)) mapfn = (config['mi_icopat'] % icold) + config['hemimappingsuffix'] srcpathfn = os.path.join(sumadir, mapfn) if os.path.exists(srcpathfn): trgpathfn = os.path.join(refdir, mapfn) if not os.path.exists(trgpathfn) or config['overwrite']: cmds.append('cp %s %s' % (srcpathfn, trgpathfn)) utils.run_cmds(cmds, env)
def run_makespec_bothhemis(config, env): refdir = config['refdir'] overwrite = config['overwrite'] icolds, hemis = _get_hemis_icolds(config) ext = format2extension(config) if hemis != ['l', 'r']: raise ValueError("Cannot run without left and right hemisphere") for icold in icolds: specs = [] for hemi in hemis: #surfprefix = '%s%sh' % (config['mi_icopat'] % icold, hemi) specfn = afni_suma_spec.canonical_filename(icold, hemi, config['alsuffix']) specpathfn = os.path.join(refdir, specfn) s = afni_suma_spec.read(specpathfn) specs.append(afni_suma_spec.read(specpathfn)) add_states = ['inflated', 'full.patch.flat', 'sphere.reg'] add_states_required = [True, False, True] # flat surface is optional for add_state, is_req in zip(add_states, add_states_required): has_state = all([len(spec.find_surface_from_state(add_state)) == 1 for spec in specs]) if not has_state: if is_req: error('cannot find state %s' % add_state) else: # skip this state print "Optional state %s not found - skipping" % add_state continue specs = afni_suma_spec.hemi_pairs_add_views(specs, add_state, ext, refdir, overwrite=overwrite) spec_both = afni_suma_spec.combine_left_right(specs) # generate spec files for both hemispheres hemiboth = 'b' specfn = afni_suma_spec.canonical_filename(icold, hemiboth, config['alsuffix']) specpathfn = os.path.join(refdir, specfn) spec_both.write(specpathfn, overwrite=overwrite) # merge left and right into one surface # and generate the spec files as well hemimerged = 'm' specfn = afni_suma_spec.canonical_filename(icold, hemimerged, config['alsuffix']) specpathfn = os.path.join(refdir, specfn) if config['overwrite'] or not os.path.exists(specpathfn): spec_merged, surfs_to_join = afni_suma_spec.merge_left_right(spec_both) spec_merged.write(specpathfn, overwrite=overwrite) full_path = lambda x:os.path.join(refdir, x) for fn_out, fns_in in surfs_to_join.iteritems(): surfs_in = [surf.read(full_path(fn)) for fn in fns_in] if all(['full.patch.flat' in fn for fn in fns_in]): # left hemi of flat; rotate 180 degrees, reposition again surfs_in[0] = surfs_in[0] * [-1, -1, 1] surfs_in = surf.reposition_hemisphere_pairs(surfs_in[0], surfs_in[1], 'm') surf_merged = surf.merge(*surfs_in) if config['overwrite'] or not os.path.exists(full_path(fn_out)): surf.write(full_path(fn_out), surf_merged) print "Merged surfaces written to %s" % fn_out
def average_fs_asc_surfs(fn1, fn2, fnout): '''averages two surfaces''' surf1 = surf.read(fn1) surf2 = surf.read(fn2) surfavg = surf1 * .5 + surf2 * .5 surf.write(fnout, surfavg)