def setup_options(self): helpString=""" twolevel_model_building A pydpiper application designed to work with longitudinal data. LSQ12 and nonlinear registration is used to create a consensus average of every subject. A second level of LSQ12 and nonlinear registrations is then used to bring all the consensus averages from each subject into their own consensus average. Some assumptions: * at least two timepoints per subject * future work should be able to extend this to allow single timepoint subjects * all images must be similar enough to allow registration The last point is particularly important: the consensus average building process aligns every image from each subject to every other image from that subject. Early developmental data or tumour data, where the first image in the series might not be alignable to the last image in the series, is thus not suited for this approach. Data is passed to the application through a CSV file. This file has one line per subject, with each scan per subject listed on the same line and separated by a comma. """ # own options go here lsq6.addLSQ6ArgumentGroup(self.parser) lsq12.addLSQ12ArgumentGroup(self.parser) nl.addNlinRegArgumentGroup(self.parser) rf.addGenRegArgumentGroup(self.parser) st.addStatsArguments(self.parser) # set help - note that the format is messed up, something that can be fixed if we upgrade # from optparse to argparse. self.parser.description = helpString
def setup_options(self): """Add option groups from specific modules""" addMBMGroup(self.parser) rf.addGenRegArgumentGroup(self.parser) lsq6.addLSQ6ArgumentGroup(self.parser) lsq12.addLSQ12ArgumentGroup(self.parser) nlin.addNlinRegArgumentGroup(self.parser) st.addStatsArguments(self.parser)
def setup_options(self): """Add option groups from specific modules""" addMBMGroup(self.parser) rf.addGenRegOptionGroup(self.parser) lsq6.addLSQ6OptionGroup(self.parser) lsq12.addLSQ12OptionGroup(self.parser) nlin.addNlinRegOptionGroup(self.parser) st.addStatsOptions(self.parser) self.parser.set_usage("%prog [options] input files")
def buildPipeline(self): # Run lsq12 registration prior to non-linear self.lsq12Params = mp.setLSQ12MinctraccParams( self.fileRes, subject_matter=self.subject_matter, reg_protocol=self.lsq12_protocol) lsq12reg = lsq12.LSQ12(self.inputFH, self.targetFH, blurs=self.lsq12Params.blurs, step=self.lsq12Params.stepSize, gradient=self.lsq12Params.useGradient, simplex=self.lsq12Params.simplex, w_translations=self.lsq12Params.w_translations, defaultDir=self.defaultDir) self.p.addPipeline(lsq12reg.p) #Resample using final LSQ12 transform and reset last base volume. res = ma.mincresample(self.inputFH, self.targetFH, likeFile=self.targetFH, argArray=["-sinc"]) self.p.addStage(res) self.inputFH.setLastBasevol(res.outputFiles[0]) lsq12xfm = self.inputFH.getLastXfm(self.targetFH) #Get registration parameters from nlin protocol, blur and register #Assume a SINGLE generation here. self.nlinParams = mp.setOneGenMincANTSParams( self.fileRes, reg_protocol=self.nlin_protocol) for b in self.nlinParams.blurs: for j in b: #Note that blurs for ANTS params in an array of arrays. if j != -1: self.p.addStage(ma.blur(self.targetFH, j, gradient=True)) self.p.addStage(ma.blur(self.inputFH, j, gradient=True)) sp = ma.mincANTS( self.inputFH, self.targetFH, defaultDir=self.defaultDir, blur=self.nlinParams.blurs[0], gradient=self.nlinParams.gradient[0], similarity_metric=self.nlinParams.similarityMetric[0], weight=self.nlinParams.weight[0], iterations=self.nlinParams.iterations[0], radius_or_histo=self.nlinParams.radiusHisto[0], transformation_model=self.nlinParams.transformationModel[0], regularization=self.nlinParams.regularization[0], useMask=self.nlinParams.useMask[0]) self.p.addStage(sp) nlinXfm = sp.outputFiles[0] #Reset last base volume to original input for future registrations. self.inputFH.setLastBasevol(setToOriginalInput=True) #Concatenate transforms to get final lsq12 + nlin. Register volume handles naming and setting of lastXfm output = self.inputFH.registerVolume(self.targetFH, "transforms") xc = ma.xfmConcat([lsq12xfm, nlinXfm], output, fh.logFromFile(self.inputFH.logDir, output)) self.p.addStage(xc)
def buildPipeline(self): lsq12LikeFH = None resolutionForLSQ12 = None if self.initModel: lsq12LikeFH = self.initModel[0] elif self.options.lsq12_likeFile: lsq12LikeFH = self.options.lsq12_likeFile if lsq12LikeFH == None and self.options.lsq12_subject_matter == None: print "\nError: the FullIterativeLSQ12Nlin module was called without specifying either an initial model, nor an lsq12_subject_matter. Currently that means that the code can not determine the resolution at which the registrations should be run. Please specify one of the two. Exiting\n" sys.exit() if not (lsq12LikeFH == None): resolutionForLSQ12 = rf.returnFinestResolution(lsq12LikeFH) lsq12module = lsq12.FullLSQ12( self.inputs, self.dirs.lsq12Dir, likeFile=lsq12LikeFH, maxPairs=self.options.lsq12_max_pairs, lsq12_protocol=self.options.lsq12_protocol, subject_matter=self.options.lsq12_subject_matter, resolution=resolutionForLSQ12) lsq12module.iterate() self.p.addPipeline(lsq12module.p) self.lsq12Params = lsq12module.lsq12Params if lsq12module.lsq12AvgFH.getMask() == None: if self.initModel: lsq12module.lsq12AvgFH.setMask(self.initModel[0].getMask()) if not self.avgPrefix: self.avgPrefix = self.options.pipeline_name # same as in MBM.py: # for now we can use the same resolution for the NLIN stages as we did for the # LSQ12 stage. At some point we should look into the subject matter option... nlinModule = nlin.initializeAndRunNLIN( self.dirs.lsq12Dir, self.inputs, self.dirs.nlinDir, avgPrefix=self.avgPrefix, createAvg=False, targetAvg=lsq12module.lsq12AvgFH, nlin_protocol=self.options.nlin_protocol, reg_method=self.options.reg_method, resolution=resolutionForLSQ12) self.p.addPipeline(nlinModule.p) self.nlinFH = nlinModule.nlinAverages[-1] self.nlinParams = nlinModule.nlinParams self.initialTarget = nlinModule.initialTarget # Now we need the full transform to go back to LSQ6 space for i in self.inputs: linXfm = lsq12module.lsq12AvgXfms[i] nlinXfm = i.getLastXfm(self.nlinFH) outXfm = st.createOutputFileName(i, nlinXfm, "transforms", "_with_additional.xfm") xc = ma.xfmConcat([linXfm, nlinXfm], outXfm, fh.logFromFile(i.logDir, outXfm)) self.p.addStage(xc) i.addAndSetXfmToUse(self.nlinFH, outXfm)
def buildPipeline(self): # Do LSQ12 alignment prior to non-linear stages if desired if self.includeLinear: self.lsq12Params = mp.setLSQ12MinctraccParams( self.fileRes, subject_matter=self.subject_matter, reg_protocol=self.lsq12_protocol) lsq12reg = lsq12.LSQ12( self.inputFH, self.targetFH, blurs=self.lsq12Params.blurs, step=self.lsq12Params.stepSize, gradient=self.lsq12Params.useGradient, simplex=self.lsq12Params.simplex, w_translations=self.lsq12Params.w_translations, defaultDir=self.defaultDir) self.p.addPipeline(lsq12reg.p) # create the nonlinear registrations self.nlinParams = mp.setNlinMinctraccParams( self.fileRes, reg_protocol=self.nlin_protocol) for b in self.nlinParams.blurs: if b != -1: self.p.addStage(ma.blur(self.inputFH, b, gradient=True)) self.p.addStage(ma.blur(self.targetFH, b, gradient=True)) for i in range(len(self.nlinParams.stepSize)): #For the final stage, make sure the output directory is transforms. if i == (len(self.nlinParams.stepSize) - 1): self.defaultDir = "transforms" nlinStage = ma.minctracc( self.inputFH, self.targetFH, defaultDir=self.defaultDir, blur=self.nlinParams.blurs[i], gradient=self.nlinParams.useGradient[i], iterations=self.nlinParams.iterations[i], step=self.nlinParams.stepSize[i], w_translations=self.nlinParams.w_translations[i], simplex=self.nlinParams.simplex[i], optimization=self.nlinParams.optimization[i]) self.p.addStage(nlinStage)
def buildPipeline(self): lsq12LikeFH = None if self.initModel: lsq12LikeFH = self.initModel[0] elif self.options.lsq12_likeFile: lsq12LikeFH = self.options.lsq12_likeFile lsq12module = lsq12.FullLSQ12(self.inputs, self.dirs.lsq12Dir, likeFile=lsq12LikeFH, maxPairs=self.options.lsq12_max_pairs, lsq12_protocol=self.options.lsq12_protocol, subject_matter=self.options.lsq12_subject_matter) lsq12module.iterate() self.p.addPipeline(lsq12module.p) self.lsq12Params = lsq12module.lsq12Params if lsq12module.lsq12AvgFH.getMask()== None: if self.initModel: lsq12module.lsq12AvgFH.setMask(self.initModel[0].getMask()) if not self.avgPrefix: self.avgPrefix = self.options.pipeline_name nlinModule = nlin.initializeAndRunNLIN(self.dirs.lsq12Dir, self.inputs, self.dirs.nlinDir, avgPrefix=self.avgPrefix, createAvg=False, targetAvg=lsq12module.lsq12AvgFH, nlin_protocol=self.options.nlin_protocol, reg_method=self.options.reg_method) self.p.addPipeline(nlinModule.p) self.nlinFH = nlinModule.nlinAverages[-1] self.nlinParams = nlinModule.nlinParams self.initialTarget = nlinModule.initialTarget # Now we need the full transform to go back to LSQ6 space for i in self.inputs: linXfm = lsq12module.lsq12AvgXfms[i] nlinXfm = i.getLastXfm(self.nlinFH) outXfm = st.createOutputFileName(i, nlinXfm, "transforms", "_with_additional.xfm") xc = ma.xfmConcat([linXfm, nlinXfm], outXfm, fh.logFromFile(i.logDir, outXfm)) self.p.addStage(xc) i.addAndSetXfmToUse(self.nlinFH, outXfm)
def run(self): options = self.options args = self.args # make sure only one of the lsq6 target options is provided lsq6.verifyCorrectLSQ6TargetOptions(options.bootstrap, options.init_model, options.lsq6_target) # if no pipeline name was provided, initialize it here with the current date # setupDirectories deals with a missing pipeline name well, but we use this variable # in some more places if not options.pipeline_name: options.pipeline_name = str(date.today()) + "_pipeline" # Setup output directories for different registration modules. dirs = rf.setupDirectories(self.outputDir, options.pipeline_name, module="ALL") inputFiles = rf.initializeInputFiles(args, dirs.processedDir, maskDir=options.mask_dir) # if we are running a bootstrap or lsq6_target option, pass in the correct target target_file_for_lsq6 = None target_file_directory = None if(options.bootstrap): target_file_for_lsq6 = inputFiles[0].inputFileName target_file_directory = fh.createSubDir(self.outputDir,options.pipeline_name + "_bootstrap_file") if(options.lsq6_target): target_file_for_lsq6 = options.lsq6_target target_file_directory = fh.createSubDir(self.outputDir,options.pipeline_name + "_target_file") #Setup init model and inital target. Function also exists if no target was specified. initModel, targetPipeFH = rf.setInitialTarget(options.init_model, target_file_for_lsq6, target_file_directory, self.outputDir, options.pipeline_name) #LSQ6 MODULE, NUC and INORM runLSQ6NucInorm = lsq6.LSQ6NUCInorm(inputFiles, targetPipeFH, initModel, dirs.lsq6Dir, options) self.pipeline.addPipeline(runLSQ6NucInorm.p) # LSQ12 MODULE # We need to specify a likeFile/space when all files are resampled # at the end of LSQ12. If one is not specified, use standard space. # However, only change this when either an initial model is specified # or when an lsq12_likefile is given. If we are running a bootstrap # or lsq6_target pipeline, we do not have to change anything # # Also provide the lsq12 module with the resolution at which this should # all happen resolutionForLSQ12 = None if options.lsq12_likeFile == None: if initModel: targetPipeFH = initModel[0] else: targetPipeFH = rfh.RegistrationFHBase(os.path.abspath(options.lsq12_likeFile), basedir=dirs.lsq12Dir) resolutionForLSQ12 = rf.returnFinestResolution(targetPipeFH) lsq12module = lsq12.FullLSQ12(inputFiles, dirs.lsq12Dir, likeFile=targetPipeFH, maxPairs=options.lsq12_max_pairs, lsq12_protocol=options.lsq12_protocol, subject_matter=options.lsq12_subject_matter, resolution=resolutionForLSQ12) lsq12module.iterate() self.pipeline.addPipeline(lsq12module.p) #TODO: Additional NUC step here. This will impact both the lsq6 and lsq12 modules. # May want to not do resampling and averaging by default. TBD. #Target mask for registration--I HATE this hack, as is noted in check-in and #as a github issue. if lsq12module.lsq12AvgFH.getMask()== None: if initModel: # if we are using an initial model, we can get that mask lsq12module.lsq12AvgFH.setMask(initModel[0].getMask()) #NLIN MODULE - Register with minctracc or mincANTS based on options.reg_method # for now we can use the same resolution for the NLIN stages as we did for the # LSQ12 stage. At some point we should look into the subject matter option... nlinObj = nlin.initializeAndRunNLIN(dirs.lsq12Dir, inputFiles, dirs.nlinDir, avgPrefix=options.pipeline_name, createAvg=False, targetAvg=lsq12module.lsq12AvgFH, nlin_protocol=options.nlin_protocol, reg_method=options.reg_method, resolution=resolutionForLSQ12) self.pipeline.addPipeline(nlinObj.p) self.nlinAverages = nlinObj.nlinAverages #STATS MODULE if options.calc_stats: #Choose final average from array of nlin averages finalNlin = self.nlinAverages[-1] # For each input file, calculate statistics from final average (finalNlin) # to the inputFH space where all linear differences have been accounted for (LSQ12). # The additionalXfm specified for each inputFH is the transform from the lsq6 to lsq12 # space for that scan. This encapsulates linear differences and is necessary for # some of the calculations in CalcStats. for inputFH in inputFiles: stats = st.CalcStats(inputFH, finalNlin, options.stats_kernels, additionalXfm=lsq12module.lsq12AvgXfms[inputFH]) self.pipeline.addPipeline(stats.p)
def run(self): options = self.options args = self.args # Setup output directories for different registration modules. dirs = rf.setupDirectories(self.outputDir, options.pipeline_name, module="ALL") inputFiles = rf.initializeInputFiles(args, dirs.processedDir, maskDir=options.mask_dir) #Setup init model and inital target. Function also exists if no target was specified. initModel, targetPipeFH = rf.setInitialTarget(options.init_model, options.lsq6_target, dirs.lsq6Dir, self.outputDir) #LSQ6 MODULE, NUC and INORM runLSQ6NucInorm = lsq6.LSQ6NUCInorm(inputFiles, targetPipeFH, initModel, dirs.lsq6Dir, options) self.pipeline.addPipeline(runLSQ6NucInorm.p) # LSQ12 MODULE # We need to specify a likeFile/space when all files are resampled # at the end of LSQ12. If one is not specified, use standard space. if options.lsq12_likeFile == None: targetPipeFH = initModel[0] else: targetPipeFH = rfh.RegistrationFHBase(os.path.abspath(options.lsq12_likeFile), basedir=dirs.lsq12Dir) lsq12module = lsq12.FullLSQ12(inputFiles, dirs.lsq12Dir, likeFile=targetPipeFH, maxPairs=None, lsq12_protocol=options.lsq12_protocol, subject_matter=options.lsq12_subject_matter) lsq12module.iterate() self.pipeline.addPipeline(lsq12module.p) #TODO: Additional NUC step here. This will impact both the lsq6 and lsq12 modules. # May want to not do resampling and averaging by default. TBD. #Target mask for registration--I HATE this hack, as is noted in check-in and #as a github issue. if lsq12module.lsq12AvgFH.getMask()== None: if initModel[0]: lsq12module.lsq12AvgFH.setMask(initModel[0].getMask()) #NLIN MODULE - Register with minctracc or mincANTS based on options.reg_method nlinObj = nlin.initializeAndRunNLIN(dirs.lsq12Dir, inputFiles, dirs.nlinDir, avgPrefix=options.pipeline_name, createAvg=False, targetAvg=lsq12module.lsq12AvgFH, nlin_protocol=options.nlin_protocol, reg_method=options.reg_method) self.pipeline.addPipeline(nlinObj.p) self.nlinAverages = nlinObj.nlinAverages #STATS MODULE if options.calc_stats: #Choose final average from array of nlin averages finalNlin = self.nlinAverages[-1] # For each input file, calculate statistics from final average (finalNlin) # to the inputFH space where all linear differences have been accounted for (LSQ12). # The additionalXfm specified for each inputFH is the transform from the lsq6 to lsq12 # space for that scan. This encapsulates linear differences and is necessary for # some of the calculations in CalcStats. for inputFH in inputFiles: stats = st.CalcStats(inputFH, finalNlin, options.stats_kernels, additionalXfm=lsq12module.lsq12AvgXfms[inputFH]) self.pipeline.addPipeline(stats.p)