def main(self): with TemporaryDirectory() as tmpdir: tmpdir = local.path(tmpdir) bse = tmpdir / "maskedbse.nrrd" t2masked = tmpdir / "maskedt2.nrrd" t2inbse = tmpdir / "t2inbse.nrrd" epiwarp = tmpdir / "epiwarp.nii.gz" t2tobse_rigid = tmpdir / "t2tobse_rigid" logging.info('1. Extract and mask the DWI b0') bse_py('-m', self.dwimask ,'-i', self.dwi ,'-o', bse) logging.info("2. Mask the T2") unu("3op", "ifelse", self.t2mask, self.t2, "0", "-o", t2masked) logging.info( "3. Compute a rigid registration from the T2 to the DWI baseline") antsRegistrationSyN_sh("-d", "3" ,"-f", bse ,"-m", t2masked ,"-t", "r" ,"-o", tmpdir / "t2tobse_rigid") antsApplyTransforms("-d", "3" ,"-i", t2masked ,"-o", t2inbse ,"-r", bse ,"-t", tmpdir / "t2tobse_rigid0GenericAffine.mat") logging.info("4. Compute 1d nonlinear registration from the DWI to the T2 along the phase direction") moving = bse fixed = t2inbse pre = tmpdir / "epi" dwiepi = tmpdir / "dwiepi"+getext(self.out) antsRegistration("-d", "3" ,"-m", "cc["+fixed+","+moving+",1,2]" ,"-t", "SyN[0.25,3,0]" ,"-c", "50x50x10" ,"-f", "4x2x1" , "-s", "2x1x0" ,"--restrict-deformation", "0x1x0" ,"-v", "1" ,"-o", pre) local.path(pre+"0Warp.nii.gz").move(epiwarp) logging.info("5. Apply warp to the DWI") antsApplyTransformsDWI_sh(self.dwi, self.dwimask, epiwarp, dwiepi) if getext(dwiepi) == '.nhdr': unu("save","-e","gzip","-f","nrrd","-i",dwiepi,self.out) else: dwiepi.move(self.out) if self.debug: tmpdir.move("epidebug-"+getpid())
def main(self): fshome = local.path(os.getenv('FREESURFER_HOME')) if not fshome: logging.error('Set FREESURFER_HOME first.') sys.exit(1) with TemporaryDirectory() as tmpdir: tmpdir = local.path(tmpdir) b0masked = tmpdir / "b0masked.nrrd" b0masked1mm = tmpdir / "b0masked1mm.nrrd" brain = tmpdir / "brain.nii.gz" wmparc = tmpdir / "wmparc.nii.gz" brainmgz = self.parent.fsdir / 'mri/brain.mgz' wmparcmgz = self.parent.fsdir / 'mri/wmparc.mgz' wmparcindwi1mm = tmpdir / 'wmparcInDwi1mm.nii.gz' logging.info( "Make brain.nii.gz and wmparc.nii.gz from their mgz versions") vol2vol = local[fshome / 'bin/mri_vol2vol'] label2vol = local[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) logging.info('Extract B0 from DWI and mask') bse_py('-i', self.parent.dwi, '-m', self.parent.dwimask, '-o', b0masked) logging.info('Made masked B0') logging.info('Upsample masked baseline to 1x1x1') ResampleImageBySpacing('3', b0masked, b0masked1mm, '1', '1', '1') logging.info('Made 1x1x1 baseline') logging.info('Register wmparc to B0') pre = tmpdir / 'fsbrain_to_b0' affine = pre + '0GenericAffine.mat' warp = pre + '1Warp.nii.gz' antsRegistrationSyNMI_sh['-m', brain, '-f', b0masked1mm, '-o', pre, '-n', 32] & FG antsApplyTransforms('-d', '3', '-i', wmparc, '-t', warp, affine, '-r', b0masked1mm, '-o', wmparcindwi1mm, '--interpolation', 'NearestNeighbor') logging.info('Made ' + wmparcindwi1mm) logging.info('Make output directory') self.parent.out.mkdir() b0masked.copy(self.parent.out) b0masked1mm.copy(self.parent.out) wmparcindwi1mm.copy(self.parent.out)
def main(self): 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.nrrd" t2masked = tmpdir / "maskedt2.nrrd" t2inbse = tmpdir / "t2inbse.nrrd" epiwarp = tmpdir / "epiwarp.nii.gz" t2tobse_rigid = tmpdir / "t2tobse_rigid" logging.info('1. Extract and mask the DWI b0') bse_py('-m', self.dwimask, '-i', self.dwi, '-o', bse) logging.info("2. Mask the T2") unu("3op", "ifelse", self.t2mask, self.t2, "0", "-o", t2masked) logging.info( "3. Compute a rigid registration from the T2 to the DWI baseline") antsRegistrationSyN_sh("-d", "3", "-f", bse, "-m", t2masked, "-t", "r", "-o", tmpdir / "t2tobse_rigid") antsApplyTransforms("-d", "3", "-i", t2masked, "-o", t2inbse, "-r", bse, "-t", tmpdir / "t2tobse_rigid0GenericAffine.mat") logging.info( "4. Compute 1d nonlinear registration from the DWI to the T2 along the phase direction") moving = bse fixed = t2inbse pre = tmpdir / "epi" dwiepi = tmpdir / ("dwiepi" + ''.join(self.out.suffixes)) 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") antsApplyTransformsDWI_py('-i', self.dwi, '-m', self.dwimask, '-t', epiwarp, '-o', dwiepi) if '.nhdr' in dwiepi.suffixes: unu("save", "-e", "gzip", "-f", "nrrd", "-i", dwiepi, self.out) else: dwiepi.move(self.out) if self.debug: tmpdir.copy(self.out.dirname / ("epidebug-" + str(getpid())))
def main(self): 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.nrrd" t2masked = tmpdir / "maskedt2.nrrd" t2inbse = tmpdir / "t2inbse.nrrd" epiwarp = tmpdir / "epiwarp.nii.gz" t2tobse_rigid = tmpdir / "t2tobse_rigid" affine = tmpdir / "t2tobse_rigid0GenericAffine.mat" logging.info('1. Extract and mask the DWI b0') bse_py('-m', self.dwimask, '-i', self.dwi, '-o', bse) logging.info("2. Mask the T2") unu("3op", "ifelse", self.t2mask, self.t2, "0", "-o", t2masked) logging.info( "3. Compute a rigid registration from the T2 to the DWI baseline" ) antsRegistrationSyN_sh("-d", "3", "-f", bse, "-m", t2masked, "-t", "r", "-o", tmpdir / "t2tobse_rigid") antsApplyTransforms("-d", "3", "-i", t2masked, "-o", t2inbse, "-r", bse, "-t", affine) logging.info( "4. Compute 1d nonlinear registration from the DWI to the T2 along the phase direction" ) moving = bse fixed = t2inbse pre = tmpdir / "epi" dwiepi = tmpdir / ("dwiepi" + ''.join(self.out.suffixes)) 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") antsApplyTransformsDWI_py['-i', self.dwi, '-m', self.dwimask, '-t', epiwarp, '-o', dwiepi, '-n', str(self.nproc)] & FG logging.info('6. Apply warp to the DWI mask') epimask = self.out.dirname / self.out.basename.split( '.')[0] + '-mask.nrrd' antsApplyTransforms('-d', '3', '-i', self.dwimask, '-o', epimask, '-n', 'NearestNeighbor', '-r', bse, '-t', epiwarp) unu('convert', '-t', 'uchar', '-i', epimask, '-o', epimask) if '.nhdr' in dwiepi.suffixes: unu("save", "-e", "gzip", "-f", "nrrd", "-i", dwiepi, "-o", self.out) else: dwiepi.move(self.out) # FIXME: the following conversion is only for UKFTractography, should be removed in future if self.typeCast: unu('convert', '-t', 'int16', '-i', self.out, '-o', self.out) 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) # fileinput() caused trouble reading data file in python 3, so switching to nrrd # if the hdr has 'nan' in space origin, the following will take care of that img = nrrd.read(self.dwi) dwi = img[0] hdr = img[1] hdr_out = hdr.copy() hdr_out['space origin'] = hdr_out['space origin'][0:3] nrrd.write('dwijoined.nhdr', dwi, header=hdr_out, compression_level=1) # we want to use this hdr to write a new .nhdr file with corresponding data file # so delete old data file from the hdr if 'data file' in hdr_out.keys(): del hdr_out['data file'] elif 'datafile' in hdr_out.keys(): del hdr_out['datafile'] if 'content' in hdr_out.keys(): del hdr_out['content'] logging.info('Dice the DWI') # Since fslmerge works along the 3rd axis only, dicing also has to be along that axis # So, use `unu permute` to reorient the volumes to be stacked along 3rd axis only # Include this issue in the tutorial (unu['convert', '-t', 'int16', '-i', 'dwijoined.nhdr'] | unu['dice', '-a', '3', '-o', 'Diffusion-G'])() vols = tmpdir.glob('Diffusion-G*.nrrd') vols.sort() logging.info('Extract the B0') bse_py('-i', 'dwijoined.nhdr', '-o', 'b0.nrrd') ConvertBetweenFileFormats('b0.nrrd', 'b0.nii.gz', 'short') logging.info('Register each volume to the B0') # 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') # ConvertBetweenFileFormats(vol, volnii, 'short') # 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', volsRegistered) transforms = tmpdir.glob('Diffusion-G*.txt') transforms.sort() # nibabel loading can be avoided by setting 'data file' = EddyCorrect-DWI.nii.gz # and 'byteskip' = -1 # Tashrif updated Pynrrd package to properly handle that new_dwi = nib.load('EddyCorrect-DWI.nii.gz').get_data() logging.info('Extract the rotations and realign the gradients') space = hdr_out['space'].lower() if (space == 'left'): spctoras = np.matrix([[-1, 0, 0], [0, -1, 0], [0, 0, 1]]) else: spctoras = np.matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) mf = np.matrix(hdr['measurement frame']) # Transforms are in RAS so need to do inv(MF)*inv(SPC2RAS)*ROTATION*SPC2RAS*MF*GRADIENT mfras = mf.I * spctoras.I rasmf = spctoras * mf for (i, t) in enumerate(transforms): gDir = [ float(num) for num in hdr_out['DWMRI_gradient_' + '{:04}'.format(i)].split(' ') if num ] 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 newdir = np.dot(mfras * rot * rasmf, gDir) hdr_out['DWMRI_gradient_' + '{:04}'.format(i)] = (' ').join( str(x) for x in newdir.tolist()[0]) tar('cvzf', outxfms, transforms) nrrd.write(self.out, new_dwi, header=hdr_out, compression_level=1) if self.debug: tmpdir.copy( join(dirname(self.out), "eddy-debug-" + 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) unu('save', '-f', 'nrrd', '-e', 'gzip', '-i', self.dwi, '-o', 'dwijoined.nhdr') logging.info('Dice the DWI') (unu['convert', '-t', 'int16', '-i', 'dwijoined.nhdr'] | unu['dice', '-a', '3', '-o', 'Diffusion-G'])() vols = tmpdir.glob('Diffusion-G*.nrrd') vols.sort() logging.info('Extract the B0') bse_py('-i', 'dwijoined.nhdr', '-o', 'b0.nrrd') ConvertBetweenFileFormats('b0.nrrd', 'b0.nii.gz', 'short') logging.info('Register each volume to the B0') volsRegistered = [] for vol in vols: volnii = vol.with_suffix('.nii.gz') ConvertBetweenFileFormats(vol, volnii, 'short') 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', volsRegistered) transforms = tmpdir.glob('Diffusion-G*.txt') transforms.sort() logging.info('Extract the rotations and realign the gradients') gDir = [] header = '' gNum = [] gframe = [] with open('dwijoined.nhdr') as f: for line in f: if line.find('DWMRI_gradient_') != -1: gNum.append(line[15:19]) gDir.append(map(float, line[21:-1].split())) elif line.find('data file:') != -1: header = header + 'data file: EddyCorrect-DWI.nii.gz\n' elif line.find('encoding:') != -1: header = header + line + 'byteskip: -1\n' elif line.find('measurement frame:') != -1: header = header + line mf = np.matrix([ map(float, line.split()[2][1:-1].split(',')), map(float, line.split()[3][1:-1].split(',')), map(float, line.split()[4][1:-1].split(',')) ]) elif line.find('space:') != -1: header = header + line # Here I assume either lps or ras so only need to check the first letter space = line.split()[1][0] if (space == 'l') | (space == 'L'): spctoras = np.matrix([[-1, 0, 0], [0, -1, 0], [0, 0, 1]]) else: spctoras = np.matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) else: header = header + line with open('EddyCorrect-DWI.nhdr', 'w') as f: f.write(header) i = 0 # Transforms are in RAS so need to do inv(MF)*inv(SPC2RAS)*ROTATION*SPC2RAS*MF*GRADIENT mfras = mf.I * spctoras.I rasmf = spctoras * mf for t in 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 # Computer 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 newdir = np.dot(mfras * rot * rasmf, gDir[i]) f.write('DWMRI_gradient_' + gNum[i] + ':= ' + str(newdir[0, 0]) + ' ' + str(newdir[0, 1]) + ' ' + str(newdir[0, 2]) + '\n') i = i + 1 tar('cvzf', outxfms, transforms) unu('save', '-f', 'nrrd', '-e', 'gzip', '-i', 'EddyCorrect-DWI.nhdr', '-o', self.out) if self.debug: tmpdir.move("eddy-debug-" + str(getpid()))