def check_csv(file, force): with open(file) as f: content = f.read() for line, row in enumerate(content.split()): dwi_mask = [element for element in row.split(',') if element] # handling w/space if len(dwi_mask) != 2: raise FileNotFoundError( f'Columns don\'t have same number of entries: check line {line} in {file}' ) dirCheckFlag = 1 for img in dwi_mask: if not exists(img): raise FileNotFoundError( f'{img} does not exist: check line {line} in {file}') elif dirCheckFlag: # create DTI and harmonization directory dtiPath = pjoin(dirname(img), 'dti') check_dir(dtiPath, force) harmPath = pjoin(dirname(img), 'harm') check_dir(harmPath, force) dirCheckFlag = 0
def play(samples_or_snd, sr=None, compress=True): if sr is None: samples = samples_or_snd.samples sr = samples_or_snd.rate else: samples = samples_or_snd snd = Sound(None, sr, samples) # .unnormalized('int16') path = ut.pjoin(imtable.get_www_path(), 'sounds') if compress: with ut.temp_file('.wav') as wav_fname: fname = ut.make_temp('.mp3', dir=path) #scipy.io.wavfile.write(wav_fname, snd.rate, snd.samples) snd.save(wav_fname) os.system('ffmpeg -loglevel error -y -i "%s" "%s"' % (wav_fname, fname)) else: fname = ut.make_temp('.wav', dir=path) scipy.io.wavfile.write(fname, snd.rate, snd.samples) os.system('chmod a+rwx %s' % fname) #url = ut.pjoin(imtable.PUBLIC_URL, 'sounds', os.path.split(fname)[1]) url = ut.pjoin(imtable.get_url(), 'sounds', os.path.split(fname)[1]) print(url) return url
def test_tour(par=1): ip.reset(par) scene = 'disrupt-11' scan = dset.Scan('../data/%s' % scene) texel_colors = ut.load(ut.pjoin(figures.make_path('noloo', 'interior-wide', scene), 'data.pk'))['ret'][0] mesh = box.load_from_mat(ut.pjoin(scan.path, 'cube.mat')) tour(scan, mesh, texel_colors, [0, 1, 2], plane_idx = 0, outline_start = 0, par = par)
def test_tour(par=1): ip.reset(par) scene = 'disrupt-11' scan = dset.Scan('../data/%s' % scene) texel_colors = ut.load( ut.pjoin(figures.make_path('noloo', 'interior-wide', scene), 'data.pk'))['ret'][0] mesh = box.load_from_mat(ut.pjoin(scan.path, 'cube.mat')) tour(scan, mesh, texel_colors, [0, 1, 2], plane_idx=0, outline_start=0, par=par)
def play(samples_or_snd, sr=None): if sr is None: samples = samples_or_snd.samples sr = samples_or_snd.rate else: samples = samples_or_snd snd = Sound(None, sr, samples).unnormalized('int16') path = ut.pjoin(imtable.WWW_PATH, 'sounds') fname = ut.make_temp('.wav', dir=path) scipy.io.wavfile.write(fname, snd.rate, snd.samples) os.system('chmod a+rwx %s' % fname) url = ut.pjoin(imtable.PUBLIC_URL, 'sounds', os.path.split(fname)[1]) print url return url
def rigid_registration(dim, moving, fixed, outPrefix): check_call((' ').join([ pjoin(FILEDIR, 'antsRegistrationSyNMI.sh'), '-d', str(dim), '-t', 'r', '-m', moving, '-f', fixed, '-o', outPrefix ]), shell=True)
def make_video(out_fname, ims, fps, tmp_ext = '.ppm'): assert tmp_ext.startswith('.') in_dir = ut.make_temp_dir_big() # for i, x in enumerate(ims): # # pad to be even # if x.shape[0] % 2 == 1 or x.shape[1] % 2 == 1: # x = ig.pad_corner(x, x.shape[1] % 2, x.shape[0] % 2) # ig.save(ut.pjoin(in_dir, 'ao-video-frame%05d%s' % (i, tmp_ext)), x) ut.parmap(make_video_helper, [(i, x, in_dir, tmp_ext) for i, x in enumerate(ims)]) cmd = 'ffmpeg -loglevel warning -f image2 -r %f -i %s/ao-video-frame%%05d%s -pix_fmt yuv420p -vcodec h264 -acodec aac -strict 2 -y %s' % (fps, in_dir, tmp_ext, out_fname) # try to make it work well in keynote (hack) #cmd = 'ffmpeg -r %f -i %s/ao-video-frame%%05d%s -y -qscale:v 0 %s' % (fps, in_dir, tmp_ext, out_fname) print cmd #print cmd os.system(cmd) #os.system('ffmpeg -f image2 -r %f -i %s/ao-video-frame%%05d%s -pix_fmt yuv420p -vcodec h264 -acodec aac -strict 2 -y %s' % (fps, in_dir, tmp_ext, out_fname)) #os.system('ffmpeg -f image2 -r %f -i %s/ao-video-frame%%05d%s -pix_fmt yuv420p -vcodec h264 -acodec aac -strict 2 -y %s' % (fps, in_dir, tmp_ext, out_fname)) if 0: print 'HACK' else: for x in glob.glob(ut.pjoin(in_dir, 'ao-video-frame*%s' % tmp_ext)): os.remove(x) os.rmdir(in_dir)
def main(self): prefix = self.dwi_file.name.split('.')[0] outPrefix = pjoin(self.outDir._path, prefix + '_Ed') if self.b0_brain_mask == 'None': logging.info('Mask not provided, creating mask ...') self.b0_brain_mask = outPrefix + '_mask.nii.gz' bet_mask(self.dwi_file, self.b0_brain_mask, 4, bvalFile=self.bvals_file, BET_THRESHOLD=self.betThreshold) eddy_openmp[f'--imain={self.dwi_file}', f'--mask={self.b0_brain_mask}', f'--acqp={self.acqparams_file}', f'--index={self.index_file}', f'--bvecs={self.bvecs_file}', f'--bvals={self.bvals_file}', f'--out={outPrefix}', '--verbose', eddy_openmp_params.split()] & FG # copy bval,bvec to have same prefix as that of eddy corrected volume copyfile(outPrefix + '.eddy_rotated_bvecs', outPrefix + '.bvec') copyfile(self.bvals_file, outPrefix + '.bval')
def make_video(out_fname, ims, fps, tmp_ext='.ppm', sound=None): # Compressed images if type(ims[0]) == type(''): #tmp_ext = '.jpg' tmp_ext = '.png' assert tmp_ext.startswith('.') in_dir = ut.make_temp_dir_big() ut.parmap(make_video_helper, [(i, x, in_dir, tmp_ext) for i, x in enumerate(ims)]) with ut.temp_file('.wav') as tmp_wav: if sound is None: sound_flags = '' else: if type(sound) != type(''): sound.save(tmp_wav) sound = tmp_wav sound_flags = '-i "%s" -shortest' % sound # removed aac flag from above, for compatibility with some wav files cmd = ( 'ffmpeg -loglevel warning -f image2 -r %f -i %s/ao-video-frame%%05d%s %s ' '-pix_fmt yuv420p -vcodec h264 -strict -2 -y %s') % ( fps, in_dir, tmp_ext, sound_flags, out_fname) print cmd if 0 == os.system(cmd): for x in glob.glob(ut.pjoin(in_dir, 'ao-video-frame*%s' % tmp_ext)): os.remove(x) os.rmdir(in_dir) else: raise RuntimeError()
class App(cli.Application): """Runs tract_querier. Output is <out>/*.vtk""" ukf = cli.SwitchAttr( ['-i', '--in'], cli.ExistingFile, help='tractography file (.vtk or .vtk.gz), must be in RAS space', mandatory=True) fsindwi = cli.SwitchAttr(['-f', '--fsindwi'], cli.ExistingFile, help='Freesurfer labelmap in DWI space (nifti)', mandatory=True) query = cli.SwitchAttr(['-q', '--query'], help='tract_querier query file (e.g. wmql-2.0.qry)', mandatory=False, default=pjoin(FILEDIR, 'wmql-2.0.qry')) out = cli.SwitchAttr(['-o', '--out'], help='output directory', mandatory=True) nproc = cli.SwitchAttr( ['-n', '--nproc'], help='''number of threads to use, if other processes in your computer becomes sluggish/you run into memory error, reduce --nproc''', default=N_PROC) def main(self): with TemporaryDirectory() as t: t = local.path(t) ukf = self.ukf fsindwi = self.fsindwi if '.gz' in self.ukf.suffix: ukf = t / 'ukf.vtk' from plumbum.cmd import gunzip (gunzip['-c', self.ukf] > ukf)() tract_querier = local['tract_querier'] tract_math = local['tract_math'] ukfpruned = t / 'ukfpruned.vtk' # tract_math(ukf, 'tract_remove_short_tracts', '2', ukfpruned) tract_math[ukf, 'tract_remove_short_tracts', '2', ukfpruned] & FG if not ukfpruned.exists(): raise Exception( "tract_math failed to make '{}'".format(ukfpruned)) self.out = local.path(self.out) if self.out.exists(): self.out.delete() self.out.mkdir() tract_querier['-t', ukfpruned, '-a', fsindwi, '-q', self.query, '-o', self.out / '_'] & FG logging.info('Convert vtk field data to tensor data') # use the following multi-processed loop pool = Pool(int(self.nproc)) pool.map_async(_activateTensors_py, self.out.glob('*.vtk')) pool.close() pool.join()
def put(self, input_file): sha = util.hash_file(input_file) target_path = util.pjoin(self.url_components.path or "/", "db", sha[0:3], sha, "contents") self.bucket.upload_file(input_file, target_path.lstrip("/")) return sha
def verifyNshmForAll(csvFile, N_shm): for imgPath in read_imgs_masks(csvFile)[0]: directory = dirname(imgPath) prefix = basename(imgPath).split('.nii')[0] bvalFile = pjoin(directory, prefix + '.bval') verifyNshm(N_shm, bvalFile)
def make_video(out_fname, ims, fps, tmp_ext='.ppm'): assert tmp_ext.startswith('.') in_dir = ut.make_temp_dir_big() # for i, x in enumerate(ims): # # pad to be even # if x.shape[0] % 2 == 1 or x.shape[1] % 2 == 1: # x = ig.pad_corner(x, x.shape[1] % 2, x.shape[0] % 2) # ig.save(ut.pjoin(in_dir, 'ao-video-frame%05d%s' % (i, tmp_ext)), x) ut.parmap(make_video_helper, [(i, x, in_dir, tmp_ext) for i, x in enumerate(ims)]) cmd = 'ffmpeg -loglevel warning -f image2 -r %f -i %s/ao-video-frame%%05d%s -pix_fmt yuv420p -vcodec h264 -acodec aac -strict 2 -y %s' % ( fps, in_dir, tmp_ext, out_fname) # try to make it work well in keynote (hack) #cmd = 'ffmpeg -r %f -i %s/ao-video-frame%%05d%s -y -qscale:v 0 %s' % (fps, in_dir, tmp_ext, out_fname) print cmd #print cmd os.system(cmd) #os.system('ffmpeg -f image2 -r %f -i %s/ao-video-frame%%05d%s -pix_fmt yuv420p -vcodec h264 -acodec aac -strict 2 -y %s' % (fps, in_dir, tmp_ext, out_fname)) #os.system('ffmpeg -f image2 -r %f -i %s/ao-video-frame%%05d%s -pix_fmt yuv420p -vcodec h264 -acodec aac -strict 2 -y %s' % (fps, in_dir, tmp_ext, out_fname)) if 0: print 'HACK' else: for x in glob.glob(ut.pjoin(in_dir, 'ao-video-frame*%s' % tmp_ext)): os.remove(x) os.rmdir(in_dir)
def render_scene(scene, texel_colors, mesh=None): scan = dset.Scan(scene) if mesh is None: mesh = load_from_mat(ut.pjoin(scan.path, 'cube.mat')) # click to toggle between the rendered image and the mesh ig.show([('cycle', [mesh.render(scan, frame, texel_colors), scan.im(frame)]) for frame in xrange(scan.length)])
def make_video_helper((i, x, in_dir, tmp_ext)): out_fname = ut.pjoin(in_dir, 'ao-video-frame%05d%s' % (i, tmp_ext)) if type(x) == type(''): f = open(out_fname, 'wb') f.write(x) f.close() else: # pad to be even x = pad_im_even(x) ig.save(out_fname, x)
def joinBshells(imgPath, ref_bvals_file=None, ref_bvals=None, sep_prefix=None): if ref_bvals_file: print('Reading reference b-shell file ...') ref_bvals = read_bvals(ref_bvals_file) print('Joining b-shells for', imgPath) imgPath = local.path(imgPath) img = load(imgPath._path) dim = img.header['dim'][1:5] inPrefix = abspath(imgPath).split('.nii')[0] directory = dirname(inPrefix) prefix = basename(inPrefix) bvalFile = inPrefix + '.bval' bvecFile = inPrefix + '.bvec' if sep_prefix: harmPrefix = pjoin(directory, sep_prefix + prefix) else: harmPrefix = inPrefix if not isfile(harmPrefix + '.bval'): copyfile(bvalFile, harmPrefix + '.bval') if not isfile(harmPrefix + '.bvec'): copyfile(bvecFile, harmPrefix + '.bvec') bvals = np.array(read_bvals(inPrefix + '.bval')) joinedDwi = np.zeros((dim[0], dim[1], dim[2], dim[3]), dtype='float32') for bval in ref_bvals: # ind= np.where(bval==bvals)[0] ind = np.where(abs(bval - bvals) <= BSHELL_MIN_DIST)[0] if bval == 0.: b0Img = load(inPrefix + '_b0.nii.gz') b0 = b0Img.get_data() for i in ind: joinedDwi[:, :, :, i] = b0 else: b0_bshell = load(harmPrefix + f'_b{int(bval)}.nii.gz').get_data() joinedDwi[:, :, :, ind] = b0_bshell[:, :, :, 1:] if not isfile(harmPrefix + '.nii.gz'): save_nifti(harmPrefix + '.nii.gz', joinedDwi, b0Img.affine, b0Img.header) else: print(harmPrefix + '.nii.gz', 'already exists, not overwritten.')
def main(self): with TemporaryDirectory() as tmpdir: tmpdir = local.path(tmpdir) pre = tmpdir / 'ants' rigidxfm = pre + '0GenericAffine.mat' check_call((' ').join([ pjoin(FILEDIR, 'antsRegistrationSyNMI.sh'), '-f', self.target, '-m', self.infile, '-t', 'r', '-o', pre, '-n', ANTSREG_THREADS ]), shell=True) antsApplyTransforms['-d', '3', '-i', self.labelmap, '-t', rigidxfm, '-r', self.target, '-o', self.out, '--interpolation', 'NearestNeighbor'] & FG
def registerFs2Dwi(tmpdir, namePrefix, b0masked, brain, wmparc, wmparc_out): pre = tmpdir / namePrefix affine = pre + '0GenericAffine.mat' warp = pre + '1Warp.nii.gz' print('Computing warp from brain.nii.gz to (resampled) baseline') check_call((' ').join([ pjoin(FILEDIR, 'antsRegistrationSyNMI.sh'), '-d', '3', '-m', brain, '-f', b0masked, '-o', pre, '-n', ANTSREG_THREADS ]), shell=True) print( 'Applying warp to wmparc.nii.gz to create (resampled) wmparcindwi.nii.gz' ) antsApplyTransforms('-d', '3', '-i', wmparc, '-t', warp, affine, '-r', b0masked, '-o', wmparc_out, '--interpolation', 'NearestNeighbor') print('Made ' + wmparc_out)
def main(self): with TemporaryDirectory() as tmpdir: tmpdir = local.path(tmpdir) pre = tmpdir / 'ants' warp = pre + '1Warp.nii.gz' affine = pre + '0GenericAffine.mat' check_call((' ').join([ pjoin(FILEDIR, 'antsRegistrationSyNMI.sh'), '-f', self.target, '-m', self.infile, '-t r' if self.reg_method == 'rigid' else '', '-o', pre ]), shell=True) xfrms = f'-t {warp} -t {affine}' if self.reg_method == 'SyN' else f'-t {affine}' antsApplyTransforms['-d', '3', '-i', self.labelmap, xfrms.split(), '-r', self.target, '-o', self.out, '--interpolation', 'NearestNeighbor'] & FG
def make_video_helper((i, x, in_dir, tmp_ext)): # pad to be even if x.shape[0] % 2 == 1 or x.shape[1] % 2 == 1: x = ig.pad_corner(x, x.shape[1] % 2, x.shape[0] % 2) ig.save(ut.pjoin(in_dir, 'ao-video-frame%05d%s' % (i, tmp_ext)), x)
def render_scene(scene, texel_colors, mesh = None): scan = dset.Scan(scene) if mesh is None: mesh = load_from_mat(ut.pjoin(scan.path, 'cube.mat')) # click to toggle between the rendered image and the mesh ig.show([('cycle', [mesh.render(scan, frame, texel_colors), scan.im(frame)]) for frame in xrange(scan.length)])
def mesh_from_path(path): return load_from_mat(ut.pjoin(path, 'cube.mat'))
def get(self, sha, output_file): target_path = util.pjoin(self.url_components.path or "/", "db", sha[0:3], sha, "contents") self.bucket.download_file(target_path.lstrip("/"), output_file)
def _activateTensors_py(vtk): vtknew = vtk.dirname / (vtk.stem[2:] + ''.join(vtk.suffixes)) check_call((' ').join([pjoin(FILEDIR, 'activateTensors.py'), vtk, vtknew]), shell=True) vtk.delete()
def main(self): if self.N_proc == '-1': self.N_proc = N_CPU # check directory existence check_dir(self.templatePath, self.force) ## check consistency of b-shells and spatial resolution ref_bvals_file = pjoin(self.templatePath, 'ref_bshell_bvalues.txt') ref_res_file = pjoin(self.templatePath, 'ref_res_file.npy') if self.ref_csv: if isfile(ref_bvals_file) and isfile(ref_res_file): remove(ref_bvals_file) remove(ref_res_file) consistencyCheck(self.ref_csv, ref_bvals_file, ref_res_file) if self.target_csv: consistencyCheck(self.target_csv, ref_bvals_file, ref_res_file) ## separate b-shells if self.ref_csv: refListOutPrefix = separateShellsWrapper(self.ref_csv, ref_bvals_file, self.N_proc) if self.target_csv: tarListOutPrefix = separateShellsWrapper(self.target_csv, ref_bvals_file, self.N_proc) ## define variables for template creation and data harmonization # variables common to all ref_bvals pipeline_vars = [ '--tar_name', self.target, '--nshm', self.N_shm, '--nproc', self.N_proc, '--template', self.templatePath, ] if self.reference: pipeline_vars.append(f'--ref_name {self.reference}') if self.N_zero: pipeline_vars.append(f'--nzero {self.N_zero}') if self.bvalMap: pipeline_vars.append(f'--bvalMap {self.bvalMap}') if self.resample: pipeline_vars.append(f'--resample {self.resample}') if self.denoise: pipeline_vars.append('--denoise') if self.travelHeads: pipeline_vars.append('--travelHeads') if self.force: pipeline_vars.append('--force') if self.debug: pipeline_vars.append('--debug') if self.verbose: pipeline_vars.append('--verbose') # the b-shell bvalues are sorted in descending order because we want to perform registration with highest bval ref_bvals = read_bvals(ref_bvals_file)[::-1] for bval in ref_bvals[:-1]: # pass the last bval which is 0. if self.create and not self.process: print('## template creation ##') check_call((' ').join([ pjoin(SCRIPTDIR, 'harmonization.py'), '--tar_list', tarListOutPrefix + f'_b{int(bval)}.csv', '--bshell_b', str(int(bval)), '--ref_list', refListOutPrefix + f'_b{int(bval)}.csv', '--create' ] + pipeline_vars), shell=True) elif not self.create and self.process: print('## data harmonization ##') check_call((' ').join([ pjoin(SCRIPTDIR, 'harmonization.py'), '--tar_list', tarListOutPrefix + f'_b{int(bval)}.csv', f'--ref_list {refListOutPrefix}_b{int(bval)}.csv' if self. ref_csv else '', '--bshell_b', str(int(bval)), '--process' ] + pipeline_vars), shell=True) elif self.create and self.process: check_call((' ').join([ pjoin(SCRIPTDIR, 'harmonization.py'), '--tar_list', tarListOutPrefix + f'_b{int(bval)}.csv', '--bshell_b', str(int(bval)), '--ref_list', refListOutPrefix + f'_b{int(bval)}.csv', '--create', '--process' ] + pipeline_vars), shell=True) if '--force' in pipeline_vars: pipeline_vars.remove('--force') ## join harmonized data if self.process: joinAllBshells(self.target_csv, ref_bvals_file, 'harmonized_', self.N_proc) if self.debug and self.ref_csv: joinAllBshells(self.ref_csv, ref_bvals_file, 'reconstructed_', self.N_proc)
def main(self): self.out = local.path(self.out) if not self.force and self.out.exists(): logging.error( '{} already exists, use --force to force overwrite.'.format( self.out)) sys.exit(1) with TemporaryDirectory() as tmpdir: tmpdir = local.path(tmpdir) bse = tmpdir / 'maskedbse.nii.gz' t2masked = tmpdir / 'maskedt2.nii.gz' t2inbse = tmpdir / 't2inbse.nii.gz' epiwarp = tmpdir / 'epiwarp.nii.gz' t2tobse_rigid = tmpdir / 't2tobse_rigid' affine = tmpdir / 't2tobse_rigid0GenericAffine.mat' logging.info('1. Extract B0 and and mask it') check_call((' ').join([ pjoin(FILEDIR, 'bse.py'), '-m', self.dwimask, '-i', self.dwi, '-o', bse ]), shell=True) logging.info('2. Mask the T2') fslmaths(self.t2mask, '-mul', self.t2, t2masked) logging.info( '3. Compute a rigid registration from the T2 to the DWI baseline' ) rigid_registration(3, t2masked, bse, t2tobse_rigid) antsApplyTransforms('-d', '3', '-i', t2masked, '-o', t2inbse, '-r', bse, '-t', affine) logging.info( '4. Compute 1d nonlinear registration from the DWI to T2-in-bse along the phase direction' ) moving = bse fixed = t2inbse pre = tmpdir / 'epi' dwiepi = tmpdir / 'dwiepi.nii.gz' antsRegistration('-d', '3', '-m', 'cc[' + str(fixed) + ',' + str(moving) + ',1,2]', '-t', 'SyN[0.25,3,0]', '-c', '50x50x10', '-f', '4x2x1', '-s', '2x1x0', '--restrict-deformation', '0x1x0', '-v', '1', '-o', pre) local.path(str(pre) + '0Warp.nii.gz').move(epiwarp) logging.info('5. Apply warp to the DWI') check_call((' ').join([ pjoin(FILEDIR, 'antsApplyTransformsDWI.py'), '-i', self.dwi, '-m', self.dwimask, '-t', epiwarp, '-o', dwiepi, '-n', self.nproc ]), shell=True) # WarpTimeSeriesImageMultiTransform can also be used # dwimasked = tmpdir / 'masked_dwi.nii.gz' # fslmaths(self.dwi, '-mul', self.dwimask, dwimasked) # WarpTimeSeriesImageMultiTransform('4', dwimasked, dwiepi, '-R', dwimasked, '-i', epiwarp) logging.info('6. Apply warp to the DWI mask') epimask = self.out._path + '-mask.nii.gz' antsApplyTransforms('-d', '3', '-i', self.dwimask, '-o', epimask, '-n', 'NearestNeighbor', '-r', bse, '-t', epiwarp) fslmaths(epimask, '-mul', '1', epimask, '-odt', 'char') dwiepi.move(self.out._path + '.nii.gz') self.bvals_file.copy(self.out._path + '.bval') self.bvecs_file.copy(self.out._path + '.bvec') if self.debug: tmpdir.copy(self.out.dirname / ('epidebug-' + str(getpid())))
def main(self): self.out = local.path(self.out) if self.out.exists(): if self.overwrite: self.out.delete() else: logging.error("{} exists, use '--force' to overwrite it".format(self.out)) sys.exit(1) outxfms = self.out.dirname / self.out.stem+'_xfms.tgz' with TemporaryDirectory() as tmpdir, local.cwd(tmpdir): tmpdir = local.path(tmpdir) dicePrefix = 'vol' logging.info('Dice the DWI') fslsplit[self.dwi] & FG logging.info('Extract the B0') check_call((' ').join([pjoin(FILEDIR,'bse.py'), '-i', self.dwi._path, '-o', 'b0.nii.gz']), shell= True) logging.info('Register each volume to the B0') vols = sorted(tmpdir // (dicePrefix + '*.nii.gz')) # use the following multi-processed loop pool= Pool(int(self.nproc)) res= pool.map_async(_Register_vol, vols) volsRegistered= res.get() pool.close() pool.join() # or use the following for loop # volsRegistered = [] # for vol in vols: # volnii = vol.with_suffix('.nii.gz') # logging.info('Run FSL flirt affine registration') # flirt('-interp' ,'sinc' # ,'-sincwidth' ,'7' # ,'-sincwindow' ,'blackman' # ,'-in', volnii # ,'-ref', 'b0.nii.gz' # ,'-nosearch' # ,'-o', volnii # ,'-omat', volnii.with_suffix('.txt', depth=2) # ,'-paddingsize', '1') # volsRegistered.append(volnii) fslmerge('-t', 'EddyCorrect-DWI.nii.gz', volsRegistered) transforms = tmpdir.glob(dicePrefix+'*.txt') transforms.sort() logging.info('Extract the rotations and realign the gradients') bvecs= read_bvecs(self.bvecFile._path) bvecs_new= bvecs.copy() for (i,t) in enumerate(transforms): logging.info('Apply ' + t) tra = np.loadtxt(t) # removes the translation aff = np.matrix(tra[0:3,0:3]) # computes the finite strain of aff to get the rotation rot = aff*aff.T # compute the square root of rot [el, ev] = np.linalg.eig(rot) eL = np.identity(3)*np.sqrt(el) sq = ev*eL*ev.I # finally the rotation is defined as rot = sq.I*aff bvecs_new[i] = np.dot(rot,bvecs[i]).tolist()[0] tar('cvzf', outxfms, transforms) # save modified bvecs write_bvecs(self.out._path+'.bvec', bvecs_new) # save EddyCorrect-DWI local.path('EddyCorrect-DWI.nii.gz').copy(self.out._path+'.nii.gz') # copy bvals self.bvalFile.copy(self.out._path+'.bval') if self.debug: tmpdir.copy(pjoin(dirname(self.out),"eddy-debug-"+str(getpid())))
def main(self): from plumbum.cmd import eddy_openmp if self.useGpu: try: from plumbum.cmd import nvcc nvcc['--version'] & FG print('\nCUDA found, looking for available GPU\n') from GPUtil import getFirstAvailable getFirstAvailable() print('available GPU found, looking for eddy_cuda executable\n' 'make sure you have created a softlink according to ' 'https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/eddy/UsersGuide') from plumbum.cmd import eddy_cuda as eddy_openmp print('\neddy_cuda executable found\n') except: print( 'nvcc, available GPU, and/or eddy_cuda was not found, using eddy_openmp' ) prefix = self.dwi_file.name.split('.')[0] self.outDir.mkdir() outPrefix = pjoin(self.outDir._path, prefix + '_Ed') if not self.b0_brain_mask: logging.info('Mask not provided, creating mask ...') self.b0_brain_mask = outPrefix + '_mask.nii.gz' bet_mask(self.dwi_file, self.b0_brain_mask, 4, bvalFile=self.bvals_file, BET_THRESHOLD=self.betThreshold) _, _, eddy_openmp_params = obtain_fsl_eddy_params( self.eddy_config_file._path) print('eddy_openmp/cuda parameters') print(eddy_openmp_params) print('') eddy_openmp[f'--imain={self.dwi_file}', f'--mask={self.b0_brain_mask}', f'--acqp={self.acqparams_file}', f'--index={self.index_file}', f'--bvecs={self.bvecs_file}', f'--bvals={self.bvals_file}', f'--out={outPrefix}', eddy_openmp_params.split()] & FG # free space, see https://github.com/pnlbwh/pnlNipype/issues/82 if '--repol' in eddy_openmp_params: rm[f'{outPrefix}.eddy_outlier_free_data.nii.gz'] & FG bvals = np.array(read_bvals(self.bvals_file)) ind = [ i for i in range(len(bvals)) if bvals[i] > B0_THRESHOLD and bvals[i] <= REPOL_BSHELL_GREATER ] if '--repol' in eddy_openmp_params and len(ind): print( '\nDoing eddy_openmp/cuda again without --repol option ' 'to obtain eddy correction w/o outlier replacement for b<=500 shells\n' ) eddy_openmp_params = eddy_openmp_params.split() eddy_openmp_params.remove('--repol') print(eddy_openmp_params) print('') wo_repol_outDir = self.outDir.join('wo_repol') wo_repol_outDir.mkdir() wo_repol_outPrefix = pjoin(wo_repol_outDir, prefix + '_Ed') eddy_openmp[ f'--imain={self.dwi_file}', f'--mask={self.b0_brain_mask}', f'--acqp={self.acqparams_file}', f'--index={self.index_file}', f'--bvecs={self.bvecs_file}', f'--bvals={self.bvals_file}', f'--out={wo_repol_outPrefix}', eddy_openmp_params] & FG repol_bvecs = np.array( read_bvecs(outPrefix + '.eddy_rotated_bvecs')) wo_repol_bvecs = np.array( read_bvecs(wo_repol_outPrefix + '.eddy_rotated_bvecs')) merged_bvecs = repol_bvecs.copy() merged_bvecs[ind, :] = wo_repol_bvecs[ind, :] repol_data = load_nifti(outPrefix + '.nii.gz') wo_repol_data = load_nifti(wo_repol_outPrefix + '.nii.gz') merged_data = repol_data.get_fdata().copy() merged_data[..., ind] = wo_repol_data.get_fdata()[..., ind] save_nifti(outPrefix + '.nii.gz', merged_data, repol_data.affine, hdr=repol_data.header) # copy bval,bvec to have same prefix as that of eddy corrected volume write_bvecs(outPrefix + '.bvec', merged_bvecs) copyfile(self.bvals_file, outPrefix + '.bval') # clean up rm['-r', wo_repol_outDir] & FG else: # copy bval,bvec to have same prefix as that of eddy corrected volume copyfile(outPrefix + '.eddy_rotated_bvecs', outPrefix + '.bvec') copyfile(self.bvals_file, outPrefix + '.bval')
def makeAtlases(target, trainingTable, outPrefix, fusion, threads, debug): with TemporaryDirectory() as tmpdir: tmpdir = local.path(tmpdir) L= len(trainingTable) multiDataFrame= pd.concat([trainingTable, pd.DataFrame({'tmpdir': [tmpdir]*L, 'target': [str(target)]*L})], axis= 1) logging.info('Create {} atlases: compute transforms from images to target and apply over images'.format(L)) pool = multiprocessing.Pool(threads) # Use all available cores, otherwise specify the number you want as an argument pool.map_async(train2target, multiDataFrame.iterrows()) pool.close() pool.join() logging.info('Fuse warped labelmaps to compute output labelmaps') atlasimages = tmpdir // 'atlas*.nii.gz' # sorting is required for applying weight to corresponding labelmap atlasimages.sort() if fusion.lower() == 'wavg': ALPHA_DEFAULT= 0.45 logging.info('Compute MI between warped images and target') pool = multiprocessing.Pool(threads) for img in atlasimages: print('MI between {} and target'.format(img)) miFile= img+'.txt' pool.apply_async(func= computeMI, args= (target, img, miFile, )) pool.close() pool.join() mis= [] with open(tmpdir+'/MI.txt','w') as fw: for img in atlasimages: with open(img+'.txt') as f: mi= f.read().strip() fw.write(img+','+mi+'\n') mis.append(float(mi)) weights = weightsFromMIExp(mis, ALPHA_DEFAULT) target_header= load_nifti(target._path).header pool = multiprocessing.Pool(threads) # Use all available cores, otherwise specify the number you want as an argument for labelname in list(trainingTable)[1:]: # list(d) gets column names out = os.path.abspath(outPrefix+ f'_{labelname}.nii.gz') if os.path.exists(out): os.remove(out) labelmaps = tmpdir // (labelname + '*') labelmaps.sort() if fusion.lower() == 'avg': print(' ') # parellelize # fuseAvg(labelmaps, out, target_header) pool.apply_async(func= fuseAvg, args= (labelmaps, out, target_header, )) elif fusion.lower() == 'antsjointfusion': print(' ') # atlasimages are the warped images # labelmaps are the warped labels # parellelize # fuseAntsJointFusion(target, atlasimages, labelmaps, out) pool.apply_async(func= fuseAntsJointFusion, args= (target, atlasimages, labelmaps, out, )) elif fusion.lower() == 'wavg': print(' ') # parellelize # fuseWeightedAvg(labelmaps, weights, out, target_header) pool.apply_async(func= fuseWeightedAvg, args= (labelmaps, weights, out, target_header, )) else: print('Unrecognized fusion option: {}. Skipping.'.format(fusion)) pool.close() pool.join() if debug: tmpdir.copy(pjoin(dirname(outPrefix), 'atlas-debug-' + str(os.getpid())))
def main(self): with tempfile.TemporaryDirectory() as tmpdir: tmpdir = local.path(tmpdir) b0masked = tmpdir / "b0masked.nii.gz" # Sylvain wants both b0maskedbrain = tmpdir / "b0maskedbrain.nii.gz" brain = tmpdir / "brain.nii.gz" wmparc = tmpdir / "wmparc.nii.gz" brainmgz = self.parent.fsdir / 'mri/brain.mgz' wmparcmgz = self.parent.fsdir / 'mri/wmparc.mgz' wmparcindwi = tmpdir / 'wmparcInDwi.nii.gz' # Sylvain wants both wmparcinbrain = tmpdir / 'wmparcInBrain.nii.gz' print( "Making brain.nii.gz and wmparc.nii.gz from their mgz versions" ) vol2vol = local[self.parent.fshome / 'bin/mri_vol2vol'] label2vol = local[self.parent.fshome / 'bin/mri_label2vol'] with local.env(SUBJECTS_DIR=''): vol2vol('--mov', brainmgz, '--targ', brainmgz, '--regheader', '--o', brain) label2vol('--seg', wmparcmgz, '--temp', brainmgz, '--regheader', wmparcmgz, '--o', wmparc) print('Extracting B0 from DWI and masking it') check_call((' ').join([ pjoin(FILEDIR, 'bse.py'), '-i', self.parent.dwi, '-m', self.parent.dwimask, '-o', b0masked ]), shell=True) print('Made masked B0') dwi_res = load_nifti( str(b0masked)).header['pixdim'][1:4].round(decimals=2) brain_res = load_nifti( str(brain)).header['pixdim'][1:4].round(decimals=2) print(f'DWI resolution: {dwi_res}') print(f'FreeSurfer brain resolution: {brain_res}') print('Registering wmparc to B0') registerFs2Dwi(tmpdir, 'fsbrainToB0', b0masked, brain, wmparc, wmparcindwi) if (dwi_res != brain_res).any(): print( 'DWI resolution is different from FreeSurfer brain resolution' ) print( 'wmparc wil be registered to both DWI and brain resolution' ) print( 'Check output files wmparcInDwi.nii.gz and wmparcInBrain.nii.gz' ) print('Resampling B0 to brain resolution') ResampleImageBySpacing('3', b0masked, b0maskedbrain, brain_res.tolist()) print('Registering wmparc to resampled B0') registerFs2Dwi(tmpdir, 'fsbrainToResampledB0', b0maskedbrain, brain, wmparc, wmparcinbrain) # copying images to outDir b0masked.copy(self.parent.out) wmparcindwi.copy(self.parent.out) if b0maskedbrain.exists(): b0maskedbrain.copy(self.parent.out) wmparcinbrain.copy(self.parent.out) if self.parent.debug: tmpdir.copy(self.parent.out, 'fs2dwi-debug-' + str(os.getpid())) print('See output files in ', self.parent.out._path)
class App(cli.Application): """Convenient script to run Freesurfer segmentation""" VERSION = __version__ t1 = cli.SwitchAttr(['-i', '--input'], cli.ExistingFile, help='t1 image in nifti format (nii, nii.gz)', mandatory=True) t1mask = cli.SwitchAttr( ['-m', '--mask'], cli.ExistingFile, help= 'mask the t1 before running Freesurfer; if not provided, -skullstrip is enabled with Freesurfer segmentation', mandatory=False) t2 = cli.SwitchAttr(['--t2'], cli.ExistingFile, help='t2 image in nifti format (nii, nii.gz)', mandatory=False) t2mask = cli.SwitchAttr( ['--t2mask'], cli.ExistingFile, help= 'mask the t2 before running Freesurfer, if t2 is provided but not its mask, -skullstrip is enabled with Freesurfer segmentation', mandatory=False) force = cli.Flag( ['-f', '--force'], help='if --force is used, any previous output will be overwritten') out = cli.SwitchAttr(['-o', '--outDir'], help='output directory', mandatory=True) ncpu = cli.SwitchAttr( ['-n', '--nproc'], help= 'number of processes/threads to use (-1 for all available) for Freesurfer segmentation', default=1) expert_file = cli.SwitchAttr( ['--expert'], cli.ExistingFile, help= 'expert options to use with recon-all for high-resolution data, see https://surfer.nmr.mgh.harvard.edu/fswiki/SubmillimeterRecon', default=pjoin(FILEDIR, 'expert_file.txt')) no_hires = cli.Flag( ['--nohires'], help= 'omit high resolution freesurfer segmentation i.e. do not use -hires flag' ) no_skullstrip = cli.Flag( ['--noskullstrip'], help= 'if you do not provide --mask but --input is already masked, omit further skull stripping by freesurfer' ) subfields = cli.Flag(['--subfields'], help='FreeSurfer 7 supported -subfields') no_rand = cli.Flag( ['--norandomness'], help='use the same random seed for certain binaries run under recon-all' ) def main(self): fshome = local.path(os.getenv('FREESURFER_HOME')) if not fshome: logging.error('Set FREESURFER_HOME first.') sys.exit(1) if not self.force and os.path.exists(self.out): logging.error( 'Output directory exists, use -f/--force to force an overwrite.' ) sys.exit(1) if self.t2mask and not self.t2: raise AttributeError('--t2mask is invalid without --t2') with TemporaryDirectory() as tmpdir, local.env(SUBJECTS_DIR=tmpdir, FSFAST_HOME='', MNI_DIR=''): tmpdir = local.path(tmpdir) if self.t1mask: logging.info('Mask the t1') t1 = tmpdir / 't1masked.nii.gz' ImageMath('3', t1, 'm', self.t1, self.t1mask) else: t1 = tmpdir / 't1.nii.gz' self.t1.copy(t1) subjid = self.t1.stem common_params = ['-s', subjid] autorecon3_params = [] if self.t2: if self.t2mask: logging.info('Mask the t2') t2 = tmpdir / 't2masked.nii.gz' ImageMath('3', t2, 'm', self.t2, self.t2mask) else: t2 = tmpdir / 't2.nii.gz' self.t2.copy(t2) autorecon3_params = ['-T2', t2, '-T2pial'] if self.subfields: autorecon3_params += ['-subfields'] logging.info("Running freesurfer on " + t1) if self.ncpu == '-1': self.ncpu = str(N_CPU) if int(self.ncpu) > 1: common_params += ['-parallel', '-openmp', self.ncpu] autorecon1_params = [] if not self.no_hires: common_params.append('-hires') autorecon1_params = ['-expert', self.expert_file] if self.no_rand: common_params.append('-norandomness') # run recon_all in three steps so we can overwrite/provide MABS masked T1 # -noskullstrip is used with -autorecon1 only, so we need to check whether T1 is masked/T1 mask is provided # irrespective of masked/unmasked T2 if self.t1mask or self.no_skullstrip: recon_all['-i', t1, common_params, '-autorecon1', autorecon1_params, '-noskullstrip'] & FG (tmpdir / subjid / 'mri/T1.mgz').copy(tmpdir / subjid / 'mri/brainmask.mgz') else: recon_all['-i', t1, common_params, '-autorecon1', autorecon1_params] & FG recon_all[common_params, '-autorecon2'] & FG recon_all[common_params, '-autorecon3', autorecon3_params] & FG logging.info("Freesurfer done.") (tmpdir / subjid).copy( self.out, override=True) # overwrites any existing directory logging.info("Made " + self.out)
def main(self): with tempfile.TemporaryDirectory() as tmpdir: tmpdir = local.path(tmpdir) b0masked = tmpdir / "b0masked.nii.gz" # Sylvain wants both b0maskedbrain = tmpdir / "b0maskedbrain.nii.gz" t2masked = tmpdir / 't2masked.nii.gz' print('Masking the T2') ImageMath(3, t2masked, 'm', self.t2, self.t2mask) brain = tmpdir / "brain.nii.gz" wmparc = tmpdir / "wmparc.nii.gz" brainmgz = self.parent.fsdir / 'mri/brain.mgz' wmparcmgz = self.parent.fsdir / 'mri/wmparc.mgz' wmparcindwi = tmpdir / 'wmparcInDwi.nii.gz' # Sylvain wants both wmparcinbrain = tmpdir / 'wmparcInBrain.nii.gz' print( "Making brain.nii.gz and wmparc.nii.gz from their mgz versions" ) vol2vol = local[self.parent.fshome / 'bin/mri_vol2vol'] label2vol = local[self.parent.fshome / 'bin/mri_label2vol'] with local.env(SUBJECTS_DIR=''): vol2vol('--mov', brainmgz, '--targ', brainmgz, '--regheader', '--o', brain) label2vol('--seg', wmparcmgz, '--temp', brainmgz, '--regheader', wmparcmgz, '--o', wmparc) print('Extracting B0 from DWI and masking it') check_call((' ').join([ pjoin(FILEDIR, 'bse.py'), '-i', self.parent.dwi, '-m', self.parent.dwimask, '-o', b0masked ]), shell=True) print('Made masked B0') # rigid registration from t2 to brain.nii.gz pre = tmpdir / 'BrainToT2' BrainToT2Affine = pre + '0GenericAffine.mat' print('Computing rigid registration from brain.nii.gz to t2') rigid_registration(3, brain, t2masked, pre) # generates three files for rigid registration: # pre0GenericAffine.mat preInverseWarped.nii.gz preWarped.nii.gz # generates five files for default(rigid+affine+deformable syn) registration: # pre0GenericAffine.mat pre1Warp.nii.gz preWarped.nii.gz pre1InverseWarp.nii.gz preInverseWarped.nii.gz dwi_res = load_nifti( str(b0masked)).header['pixdim'][1:4].round(decimals=2) brain_res = load_nifti( str(brain)).header['pixdim'][1:4].round(decimals=2) print(f'DWI resolution: {dwi_res}') print(f'FreeSurfer brain resolution: {brain_res}') print('Registering wmparc to B0 through T2') registerFs2Dwi_T2(tmpdir, 'fsbrainToT2ToB0', b0masked, t2masked, BrainToT2Affine, wmparc, wmparcindwi) if (dwi_res != brain_res).any(): print( 'DWI resolution is different from FreeSurfer brain resolution' ) print( 'wmparc wil be registered to both DWI and brain resolution' ) print( 'Check output files wmparcInDwi.nii.gz and wmparcInBrain.nii.gz' ) print('Resampling B0 to brain resolution') ResampleImageBySpacing('3', b0masked, b0maskedbrain, brain_res.tolist()) print('Registering wmparc to resampled B0') registerFs2Dwi_T2(tmpdir, 'fsbrainToT2ToResampledB0', b0maskedbrain, t2masked, BrainToT2Affine, wmparc, wmparcinbrain) # copying images to outDir b0masked.copy(self.parent.out) wmparcindwi.copy(self.parent.out) if b0maskedbrain.exists(): b0maskedbrain.copy(self.parent.out) wmparcinbrain.copy(self.parent.out) if self.parent.debug: tmpdir.copy(self.parent.out, 'fs2dwi-debug-' + str(os.getpid())) print('See output files in ', self.parent.out._path)
def get(self, sha, output_file): target_path = util.pjoin(self.url.rstrip("/"), "db", sha[0:3], sha, "contents") self.download(target_path, output_file)