def read_imgs(file, n): imgs=[] with open(file) as f: content = f.read() for line, row in enumerate(content.split()): temp = [element for element in row.split(',') if element] # handling w/space if len(temp) != n: raise FileNotFoundError(f'Columns don\'t have same number of entries: check line {line} in {file}') for img in temp: if not isfile(img): raise FileNotFoundError(f'{img} does not exist: check line {line} in {file}') imgs.append(temp) return np.array(imgs)
def show_progress(verbose=False): config = ConfigParser() config.read(pjoin(FILEDIR, 'config.ini')) outDir = config['DEFAULT']['outDir'] modalities = [x for x in config['DEFAULT']['modalities'].split(',')] # read caselist cases = read_cases(pjoin(outDir, 'log', 'caselist.txt')) num_cases = len(cases) # read start time start_time_file = pjoin(outDir, 'log', 'start_time.txt') start_time = read_time(start_time_file) # read final time final_time_file = pjoin(outDir, 'log', 'final_time.txt') if isfile(final_time_file): final_time = read_time(final_time_file) else: final_time = datetime.now() print('Output directory: ', outDir) print('Number of cases to process: ', num_cases) for modality in modalities: modality_progress(outDir, modality, num_cases, verbose) # show duration duration_in_seconds = (final_time - start_time).total_seconds() days = divmod(duration_in_seconds, 86400) hours = divmod(days[1], 3600) # Use remainder of days to calc hours minutes = divmod(hours[1], 60) # Use remainder of hours to calc minutes seconds = divmod(minutes[1], 1) # Use remainder of minutes to calc seconds print( "\nTime taken so far: %d days, %d hours, %d minutes and %d seconds\n" % (days[0], hours[0], minutes[0], seconds[0]))
def process(args): cases= read_cases(args.caselist) cases.sort() # organize images into different directories =========================================================== # outDir # | # ------------------------------------------------------------------------------------------------------ # | | | | | | | | # | | | | | | | | # transform template FA MD AD RD log stats # | (same inner file structure as that of FA) # | # ---------------------------------------- # | | | | | # preproc origdata warped skeleton roi # # copy all FA into FA directory # put all preprocessed data into preproc directory # keep all warp/affine in transform directory # output all warped images in warped directory # output all skeletons in skel directory # output ROI based analysis files in roi directory # save all ROI statistics, mean, and combined images # define directories modDir = pjoin(args.outDir, f'{args.modality}') # args.xfrmDir = pjoin(args.outDir, 'transform') # args.statsDir = pjoin(args.outDir, 'stats') templateDir = pjoin(args.outDir, 'template/') # trailing slash is important for antsMultivariate*.sh preprocDir= pjoin(modDir, 'preproc') warpDir= pjoin(modDir, 'warped') skelDir= pjoin(modDir, 'skeleton') roiDir= pjoin(modDir, 'roi') # force creation of inner directories makeDirectory(warpDir, True) makeDirectory(skelDir, True) makeDirectory(roiDir, True) # modality can be one of [FA,MD,AD,RD] # we could use just listdir(), but the following would be stricter and safer # since cases are sorted and we named images as modDir/{c}.nii.gz # the following sort puts modImgs in the same order as that of cases modImgs = glob(pjoin(modDir, '*.nii.gz')) modImgs.sort() if not args.noFillHole: print('\nFilling holes inside the brain region in diffusion measure images') # fill holes in all modality images # caveat: origdata no longer remain origdata, become hole filled origdata pool= Pool(args.ncpu) pool.map_async(fillHoles, modImgs, error_callback= RAISE) pool.close() pool.join() # preprocessing ======================================================================================== if args.modality=='FA': print('Preprocessing FA images: eroding them and zeroing the end slices ...') modDir= pjoin(args.outDir, args.modality) CURRDIR= getcwd() chdir(modDir) check_call('tbss_1_preproc *.nii.gz', shell= True) # creates 'FA' and 'origdata' folders chdir(CURRDIR) print('Index file location has changed, see ', pjoin(preprocDir, 'slicesdir', 'index.html')) # rename args.modality/FA to args.modality/preproc move(pjoin(modDir, 'FA'), preprocDir) else: print(f'Preprocessing {args.modality} images using FA mask (eroding them and zeroing the end slices) ...') modDir = pjoin(args.outDir, args.modality) # force creation of inner directories makeDirectory(pjoin(modDir, 'origdata'), True) makeDirectory(pjoin(modDir, 'preproc'), True) pool= Pool(args.ncpu) for c, imgPath in zip(cases, modImgs): FAmask= pjoin(args.outDir, 'FA', 'preproc', f'{c}_FA_mask.nii.gz') preprocMod= pjoin(preprocDir, f'{c}_{args.modality}.nii.gz') pool.apply_async(_fslmask, (imgPath, FAmask, preprocMod), error_callback= RAISE) pool.close() pool.join() check_call((' ').join(['mv', pjoin(modDir, '*.nii.gz'), pjoin(modDir, 'origdata')]), shell= True) modImgs = glob(pjoin(preprocDir, f'*{args.modality}.nii.gz')) modImgs.sort() # create template ====================================================================================== if not args.template and args.modality=='FA': print('Creating study specific template ...') # we could pass modImgs directly to antsMult(), instead saving them to a .txt file for logging # modImgs = glob(pjoin(preprocDir, f'*{args.modality}*.nii.gz')) makeDirectory(templateDir, args.force) antsMultCaselist = pjoin(args.logDir, 'antsMultCaselist.txt') with open(antsMultCaselist, 'w') as f: for imgPath in modImgs: f.write(imgPath+'\n') # ATTN: antsMultivariateTemplateConstruction2.sh requires '/' at the end of templateDir antsMult(antsMultCaselist, templateDir, args.logDir, args.ncpu, args.verbose) # TODO: rename the template args.template= pjoin(templateDir, 'template0.nii.gz') check_call(f'ln -s {args.template} {args.statsDir}', shell= True) # warp and affine to template0.nii.gz have been created for each case during template construction # so template directory should be the transform directory args.xfrmDir= templateDir # register each image to the template ================================================================== elif args.template: # find warp and affine of FA image to args.template for each case if args.modality=='FA': print(f'Registering FA images to {args.template} space ..') makeDirectory(args.xfrmDir, True) pool= Pool(args.ncpu) for c, imgPath in zip(cases, modImgs): pool.apply_async(antsReg, (args.template, imgPath, pjoin(args.xfrmDir, f'{c}_FA'), args.logDir, args.verbose), error_callback= RAISE) pool.close() pool.join() # register template to a standard space ================================================================ # useful when you would like to do ROI based analysis using an atlas # project the created/specified template to the space of atlas if args.space: outPrefix = pjoin(args.xfrmDir, 'tmp2space') warp2space = outPrefix + '1Warp.nii.gz' trans2space = outPrefix + '0GenericAffine.mat' if not isfile(warp2space): print(f'Registering {args.template} to the space of {args.space} ...') antsReg(args.space, args.template, outPrefix, args.logDir, args.verbose) # TODO: rename the template args.template = outPrefix + 'Warped.nii.gz' if basename(args.template) not in listdir(args.statsDir): check_call(f'ln -s {args.template} {args.statsDir}', shell= True) pool= Pool(args.ncpu) for c, imgPath in zip(cases, modImgs): # generalize warp and affine warp2tmp= glob(pjoin(args.xfrmDir, f'{c}_FA*1Warp.nii.gz'))[0] trans2tmp= glob(pjoin(args.xfrmDir, f'{c}_FA*0GenericAffine.mat'))[0] output= pjoin(warpDir, f'{c}_{args.modality}_to_target.nii.gz') if not args.space: # print(f'Warping {imgPath} to template space ...') pool.apply_async(_antsApplyTransforms, (imgPath, output, args.template, warp2tmp, trans2tmp), error_callback= RAISE) else: # print(f'Warping {imgPath} to template-->standard space ...') pool.apply_async(_antsApplyTransforms, (imgPath, output, args.space, warp2tmp, trans2tmp, warp2space, trans2space), error_callback= RAISE) pool.close() pool.join() # create skeleton for each subject modImgsInTarget= glob(pjoin(warpDir, f'*_{args.modality}_to_target.nii.gz')) modImgsInTarget.sort() miFile= None if args.modality=='FA': print(f'Logging MI between warped images {warpDir}/*.nii.gz and target {args.template} ...') miFile= measureSimilarity(modImgsInTarget, cases, args.template, args.logDir, args.ncpu) # obtain modified args from skeletonize() which will be used for other modalities than FA args= skeletonize(modImgsInTarget, cases, args, skelDir, miFile) skelImgsInSub= glob(pjoin(skelDir, f'*_{args.modality}_to_target_skel.nii.gz')) skelImgsInSub.sort() # roi based analysis if args.labelMap: roi_analysis(skelImgsInSub, cases, args, roiDir, args.ncpu) return args
from tbssUtil import pjoin, RAISE, environ, isfile from plumbum.cmd import antsRegistration, MeasureImageSimilarity, head, cut from plumbum import FG from multiprocessing import Pool import numpy as np # determine ANTS_VERSION # $ antsRegistration --version # ANTs Version: 2.2.0.dev233-g19285 # Compiled: Sep 2 2018 23:23:33 antsVerFile = '/tmp/ANTS_VERSION_' + environ['USER'] if not isfile(antsVerFile): (antsRegistration['--version'] > antsVerFile) & FG with open(antsVerFile) as f: content = f.read().split('\n') ANTS_VERSION = content[0].split()[-1] def computeMI(target, img, miFile): if ANTS_VERSION <= '2.1.0': (MeasureImageSimilarity['3', '2', target, img] | head['-n', '-2'] | cut['-d ', '-f6'] > miFile)() else: (MeasureImageSimilarity['-d', '3', '-m', 'MI[{},{},1,256]'.format(target, img)] > miFile) & FG