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):
        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
Beispiel #3
0
 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)
Beispiel #4
0
 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)
Beispiel #5
0
 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") 
Beispiel #6
0
 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") 
Beispiel #7
0
    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)
Beispiel #8
0
    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)
Beispiel #9
0
    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)
Beispiel #10
0
 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)
Beispiel #11
0
    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)
Beispiel #12
0
 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)