コード例 #1
0
def deep_segment(
    image: FileAtom,
    deep_segment_pipeline: FileAtom,
    anatomical_suffix: str,
    count_suffix: str,
    outline_suffix: str = None,
    cell_min_area: int = None,
    cell_mean_area: float = None,
    cell_max_area: int = None,
    temp_dir: str = None,
):
    anatomical = image.newname_with_suffix("_" + anatomical_suffix)
    count = image.newname_with_suffix("_" + count_suffix)
    outline = image.newname_with_suffix(
        "_" + outline_suffix) if outline_suffix else None
    stage = CmdStage(inputs=(image, deep_segment_pipeline),
                     outputs=(anatomical, count),
                     cmd=['deep_segment.py',
                          '--segment-intensity 1',
                          '--temp-dir %s' % temp_dir if temp_dir else "",
                          '--learner %s' % deep_segment_pipeline.path,
                          '--image %s' % image.path,
                          '--image-output %s' % anatomical.path,
                          '--centroids-output %s' % count.path,
                          '--outlines-output %s' % outline.path if outline_suffix else ""
                          '--cell-min-area %s' % cell_min_area if cell_min_area else "",
                          '--process-clusters --cell-mean-area %s --cell-max-area %s' % (cell_mean_area, cell_max_area)\
                              if (cell_mean_area and cell_max_area) else ""
                          ])
    return Result(stages=Stages([stage]), output=(anatomical, count, outline))
コード例 #2
0
ファイル: stages.py プロジェクト: MRImagingLi/pydpiper
def parse(cmd_str : str) -> CmdStage:
    """Create a CmdStage object from a string.  (Per Jason's suggestion, we could make
    an even more clever parser that simply guesses the output based on position
    or a few flags like -o and tags anything else that looks like a file as input.)
    >>> val = 2
    >>> c = parse('mincfoo -flag {val} ,input1.mnc ,input2.mnc @output.mnc'.format(**vars()))
    >>> c.outputs
    ['output.mnc']
    >>> c.inputs
    ['input1.mnc', 'input2.mnc']
    """
    cmd = shlex.split(cmd_str)
    inputs  = tuple([FileAtom(s[1:]) for s in cmd if s[0] == ','])  #TODO what about I(), O() ?
    outputs = tuple([FileAtom(s[1:]) for s in cmd if s[0] == '@'])
    s = CmdStage(inputs = inputs, outputs = outputs, cmd = [c if c[0] not in [',','@'] else c[1:] for c in cmd])
    return s
コード例 #3
0
ファイル: thickness.py プロジェクト: psteadman/pydpiper
def surface_mask2(input   : MincAtom,
                  surface : FileAtom,
                  args    : List[str] = []) -> Result[MincAtom]:
    mask_vol = surface.newname_with_suffix("_mask", ext=".mnc")
    stage = CmdStage(inputs=(input, surface),
                     outputs=(mask_vol,),
                     cmd=["surface_mask2", "-clobber"] + args + [input.path, surface.path, mask_vol.path])
    return Result(stages=Stages([stage]), output=mask_vol)
コード例 #4
0
ファイル: thickness.py プロジェクト: MRImagingLi/pydpiper
def surface_mask2(input: MincAtom,
                  surface: FileAtom,
                  args: List[str] = []) -> Result[MincAtom]:
    mask_vol = surface.newname_with_suffix("_mask", ext=".mnc")
    stage = CmdStage(inputs=(input, surface),
                     outputs=(mask_vol, ),
                     cmd=["surface_mask2", "-clobber"] + args +
                     [input.path, surface.path, mask_vol.path])
    return Result(stages=Stages([stage]), output=mask_vol)
コード例 #5
0
ファイル: thickness.py プロジェクト: MRImagingLi/pydpiper
def transform_objects(
        input_obj: FileAtom,
        xfm: XfmAtom) -> Result[FileAtom]:  # XfmAtom -> XfmHandler??
    output_obj = input_obj.newname_with_suffix("_resampled_via_%s" %
                                               xfm.filename_wo_ext)
    stage = CmdStage(
        inputs=(input_obj, xfm),
        outputs=(output_obj, ),
        cmd=["transform_objects", input_obj.path, xfm.path, output_obj.path])
    return Result(stages=Stages([stage]), output=output_obj)
コード例 #6
0
ファイル: thickness.py プロジェクト: psteadman/pydpiper
def make_laplace_grid(input_labels   : FileAtom,
                      label_mapping  : FileAtom,
                      binary_closing : bool = None,
                      side           : Optional[Side] = None):
    out_grid = input_labels.newname_with_suffix("_laplace_grid" + ("_%s" % side.name if side else ""))

    s = CmdStage(inputs=(input_labels, label_mapping), outputs=(out_grid,),
                 cmd=["make_laplace_grid", "--clobber"]
                     + optional(binary_closing, "--binary_closing")
                     + optional(side, "--%s" % side.name)
                     + [input_labels.path, label_mapping.path, out_grid.path])

    return Result(stages=Stages([s]), output=out_grid)
コード例 #7
0
def tv_slice_recon_pipeline(options):
    output_dir = options.application.output_directory
    pipeline_name = options.application.pipeline_name

    s = Stages()

    df = pd.read_csv(options.application.csv_file,
                     dtype={
                         "brain_name": str,
                         "brain_directory": str
                     })
    # transforms = (mbm_result.xfms.assign(
    #     native_file=lambda df: df.rigid_xfm.apply(lambda x: x.source),

    df["mosaic_file"] = df.apply(lambda row: find_mosaic_file(row), axis=1)
    df["mosaic_dictionary"] = df.apply(
        lambda row: read_mosaic_file(row.mosaic_file), axis=1)
    df["number_of_slices"] = df.apply(
        lambda row: int(row.mosaic_dictionary["sections"]), axis=1)
    df["interslice_distance"] = df.apply(
        lambda row: float(row.mosaic_dictionary["sectionres"]) / 1000, axis=1)
    df["Zstart"] = df.apply(lambda row: 1 if isnan(row.Zstart) else row.Zstart,
                            axis=1)
    df["Zend"] = df.apply(lambda row: row.number_of_slices - row.Zstart + 1
                          if isnan(row.Zend) else row.Zend,
                          axis=1)
    df["slice_directory"] = df.apply(lambda row: os.path.join(
        output_dir, pipeline_name + "_stitched", row.brain_name),
                                     axis=1)

    #############################
    # Step 1: Run TV_stitch.py
    #############################
    #TODO surely theres a way around this?
    df = df.assign(TV_stitch_result="")
    for index, row in df.iterrows():
        df.at[index, "TV_stitch_result"] = s.defer(
            TV_stitch_wrap(brain_directory=FileAtom(row.brain_directory),
                           brain_name=row.brain_name,
                           slice_directory=row.slice_directory,
                           TV_stitch_options=options.TV_stitch,
                           Zstart=row.Zstart,
                           Zend=row.Zend,
                           output_dir=output_dir))
    df.drop(["mosaic_dictionary", "TV_stitch_result"],
            axis=1).to_csv("TV_brains.csv", index=False)
    df.explode("TV_stitch_result")\
        .assign(slice=lambda df: df.apply(lambda row: row.TV_stitch_result.path, axis=1))\
        .drop(["mosaic_dictionary", "TV_stitch_result"], axis=1)\
        .to_csv("TV_slices.csv", index=False)
    return Result(stages=s, output=())
コード例 #8
0
ファイル: thickness.py プロジェクト: psteadman/pydpiper
def diffuse(obj_file      : FileAtom,
            input_signal  : FileAtom,
            #output_signal : FileAtom,
            kernel        : Optional[float] = None,
            iterations    : Optional[int]   = None,
            parametric    : Optional[int]   = None):
    output_signal = input_signal.newname_with_suffix("_thickness")
    stage = CmdStage(inputs=(obj_file, input_signal), outputs=(output_signal,),
                     cmd=["diffuse"]  # TODO make an abstraction for this; see Nix stdlib's `optional`
                         + ["-kernel", str(kernel)] if kernel is not None else []
                         + ["-iterations", iterations] if iterations is not None else []
                         + ["-parametric", parametric] if parametric is not None else []
                         + [obj_file, input_signal, output_signal])
    return Result(stages=Stages([stage]), output=output_signal)
コード例 #9
0
def TV_stitch_wrap(brain_directory: FileAtom, brain_name: str,
                   slice_directory: str, TV_stitch_options, Zstart: int,
                   Zend: int, output_dir: str):
    #TODO inputs should be tiles not just brain_directory
    stitched = []
    for z in range(Zstart, Zend + 1):
        slice_stitched = FileAtom(
            os.path.join(slice_directory, brain_name + "_Z%04d.tif" % z))
        stitched.append(slice_stitched)

    stage = CmdStage(
        inputs=(brain_directory, ),
        outputs=tuple(stitched),
        cmd=[
            'TV_stitch.py',
            '--clobber',
            #'--verbose',
            '--Zstart %s' % Zstart,
            '--Zend %s' % Zend,
            '--save_positions_file %s_positions.txt' %
            os.path.join(stitched[0].dir, brain_name + '_Zstart' + str(Zstart))
            if TV_stitch_options.save_positions_file else "",
            '--keeptmp' if TV_stitch_options.keep_tmp else "",
            '--scaleoutput %s' % TV_stitch_options.scale_output
            if TV_stitch_options.scale_output else '',
            # '--skip_tile_match' if TV_stitch_options.skip_tile_match else '',
            # '--Ystart %s' % TV_stitch_options.Ystart if TV_stitch_options.Ystart else '',
            # '--Yend %s' % TV_stitch_options.Yend if TV_stitch_options.Yend else '',
            # '--Xstart %s' % TV_stitch_options.Xstart if TV_stitch_options.Xstart else '',
            # '--Xend %s' % TV_stitch_options.Xend if TV_stitch_options.Xend else '',
            # '--nogradimag' if TV_stitch_options.no_gradient_image else '',
            # '--use_positions_file %s' % TV_stitch_options.use_positions_file
            # if TV_stitch_options.use_positions_file else '',
            # '--overlapx %s' % TV_stitch_options.overlapx if TV_stitch_options.overlapx else '',
            # '--overlapy %s' % TV_stitch_options.overlapy if TV_stitch_options.overlapy else '',
            # '--channel %s' % TV_stitch_options.channel if TV_stitch_options.channel else '',
            # '--Zref %s' % TV_stitch_options.Zref if TV_stitch_options.Zref else '',
            # '--Zstack_pzIcorr' if TV_stitch_options.inormalize_piezo_stack else '',
            # '--fastpiezo' if TV_stitch_options.fast_piezo else '',
            # '--short' if TV_stitch_options.short_int else '',
            # '--file_type %s' % TV_stitch_options.use_positions_file if TV_stitch_options.use_positions_file else '',
            # '--TV_file_type %s' % TV_stitch_options.use_positions_file if TV_stitch_options.use_positions_file el
            # '--use_IM' if TV_stitch_options.use_imagemagick else '',
            os.path.join(brain_directory.path, brain_name),
            os.path.join(stitched[0].dir, brain_name)
        ],
        log_file=os.path.join(output_dir, "TV_stitch.log"))

    return Result(stages=Stages([stage]), output=(stitched))
コード例 #10
0
ファイル: thickness.py プロジェクト: MRImagingLi/pydpiper
def make_laplace_grid(input_labels: FileAtom,
                      label_mapping: FileAtom,
                      binary_closing: bool = None,
                      side: Optional[Side] = None):
    out_grid = input_labels.newname_with_suffix("_laplace_grid" +
                                                ("_%s" %
                                                 side.name if side else ""))

    s = CmdStage(inputs=(input_labels, label_mapping),
                 outputs=(out_grid, ),
                 cmd=["make_laplace_grid", "--clobber"] +
                 optional(binary_closing, "--binary_closing") +
                 optional(side, "--%s" % side.name) +
                 [input_labels.path, label_mapping.path, out_grid.path])

    return Result(stages=Stages([s]), output=out_grid)
コード例 #11
0
ファイル: thickness.py プロジェクト: psteadman/pydpiper
def decimate(in_obj : FileAtom,
             reduction : float,
             smoothing_method     : Optional[Smoothing] = None,
             smoothing_iterations : Optional[int] = None):

    decimated = in_obj.newname_with_suffix("_decimated_%s" % reduction
                                           + ("_smooth" if smoothing_method not in (Smoothing.none, None) else ""))

    stage = CmdStage(inputs=(in_obj,), outputs=(decimated,),
                     cmd=["decimate.py"]
                         + (["--smoothing-method", smoothing_method.name]
                            if smoothing_method not in ("none", None) else [])
                         + (["--smoothing-iterations", str(smoothing_iterations)]
                            if smoothing_iterations is not None else [])
                         + [str(reduction), in_obj.path, decimated.path])

    return Result(stages=Stages([stage]), output=decimated)
コード例 #12
0
ファイル: thickness.py プロジェクト: MRImagingLi/pydpiper
def decimate(in_obj: FileAtom,
             reduction: float,
             smoothing_method: Optional[Smoothing] = None,
             smoothing_iterations: Optional[int] = None):

    decimated = in_obj.newname_with_suffix("_decimated_%s" % reduction + (
        "_smooth" if smoothing_method not in (Smoothing.none, None) else ""))

    stage = CmdStage(inputs=(in_obj, ),
                     outputs=(decimated, ),
                     cmd=["decimate.py"] +
                     (["--smoothing-method", smoothing_method.name]
                      if smoothing_method not in ("none", None) else []) +
                     (["--smoothing-iterations",
                       str(smoothing_iterations)]
                      if smoothing_iterations is not None else []) +
                     [str(reduction), in_obj.path, decimated.path])

    return Result(stages=Stages([stage]), output=decimated)
コード例 #13
0
ファイル: thickness.py プロジェクト: MRImagingLi/pydpiper
def diffuse(
        obj_file: FileAtom,
        input_signal: FileAtom,
        #output_signal : FileAtom,
        kernel: Optional[float] = None,
        iterations: Optional[int] = None,
        parametric: Optional[int] = None):
    output_signal = input_signal.newname_with_suffix("_thickness")
    stage = CmdStage(
        inputs=(obj_file, input_signal),
        outputs=(output_signal, ),
        cmd=[
            "diffuse"
        ]  # TODO make an abstraction for this; see Nix stdlib's `optional`
        + ["-kernel", str(kernel)] if kernel is not None else [] +
        ["-iterations", iterations] if iterations is not None else [] +
        ["-parametric", parametric] if parametric is not None else [] +
        [obj_file, input_signal, output_signal])
    return Result(stages=Stages([stage]), output=output_signal)
コード例 #14
0
ファイル: thickness.py プロジェクト: MRImagingLi/pydpiper
def marching_cubes(in_volume: MincAtom,
                   min_threshold: float = None,
                   max_threshold: float = None,
                   threshold: float = None):

    if not xor(threshold is None, min_threshold is None
               and max_threshold is None):
        raise ValueError("specify either threshold or min and max thresholds")

    out_volume = FileAtom(
        in_volume.newname_with(NotImplemented)
    )  # forget MINCy fields  # FIXME this coercion doesn't work

    stage = CmdStage(
        inputs=(in_volume, ),
        outputs=(out_volume, ),
        cmd=["marching_cubes", in_volume.path, out_volume.path] +
        ([str(threshold)] if threshold is not None else
         [str(min_threshold), str(max_threshold)]))

    return Result(stages=Stages([stage]), output=out_volume)
コード例 #15
0
def saddle_recon_pipeline(options):

    output_dir = options.application.output_directory
    pipeline_name = options.application.pipeline_name
    fid_input_dir = options.saddle_recon.varian_recon.fid_input_directory

    # TODO check that the varian recon "output_file_name" doesn't name a directory, or if it does, that it matches the output directory

    #The input directory should contain a host of fid files that will be used for the reconstruction of the mnc files
    # TODO check that there are fid files in this directory
    # TODO check that all mandatory inputs are provided
    #Make list of input fid files, with location, and create a "FileAtom" type
    varian_fid_files = [
        fid_input_dir + "/fid" + str(num_fid)
        for num_fid in range(0, options.saddle_recon.varian_recon.num_fids)
    ]
    fids = [FileAtom(name) for name in varian_fid_files]

    # Varian recon will spit out images of the format <output_file_name>.<coil#>.<rep#>.mnc
    # TODO If .mnc isn't provided at the end of the output_file_name, then there is no "." before the coil number. Need to check and correct for this.
    # Al/ the files created will be spit out to the output_dir
    # Create list of files we expect to be produced by varian recon
    coil_list_0based = [
        int(x) for x in options.saddle_recon.varian_recon.mouse_list.split(',')
    ]
    coil_list = [x + 1 for x in coil_list_0based]
    file_name_base = os.path.splitext(
        options.saddle_recon.varian_recon.output_file_name)[0]
    varian_mnc_output = [
        os.path.join(
            output_dir,
            file_name_base + "." + str(coil) + "_" + str(rep) + ".mnc")
        for coil in coil_list
        for rep in range(0, options.saddle_recon.varian_recon.num_reps)
    ]
    varian_coil_output = [
        str(coil) for coil in coil_list
        for rep in range(0, options.saddle_recon.varian_recon.num_reps)
    ]
    recon_sub_dir = [
        file_name[:-6] + "_processed" for file_name in varian_mnc_output
    ]
    imgs = [
        MincAtom(varian_mnc_output[k], pipeline_sub_dir=recon_sub_dir[k])
        for k in range(0, len(varian_mnc_output))
    ]

    s = Stages()

    #############################
    # Step 1: Run varian_recon.py
    #############################
    varian_recon_results = s.defer(
        varian_recon_ge3dmice_saddle(
            fids=fids,
            imgs=imgs,
            varian_recon_options=options.saddle_recon.varian_recon,
            output_dir=output_dir))

    # Hold results obtained in the loop
    all_lsq6_results = []
    all_dc_results = []
    all_crop_results = []

    # Loop through all the coils
    for icoil in coil_list:
        icoil_imgs = numpy.array(imgs)[numpy.where(
            numpy.array(varian_coil_output) == str(icoil))[0]]
        icoil_varian_mnc_output = numpy.array(varian_mnc_output)[numpy.where(
            numpy.array(varian_coil_output) == str(icoil))[0]]

        ###########################
        # Step 2: lsq6 registration
        ###########################
        # TODO change functionality of get_resolution_from_file so that it can be deferred
        lsq6_dir = os.path.join(output_dir,
                                file_name_base + "." + str(icoil) + "_lsq6")
        target_dir = os.path.join(
            output_dir, file_name_base + "." + str(icoil) + "_target_file")

        resolution = options.registration.resolution
        #resolution = (options.registration.resolution or
        #              get_resolution_from_file(icoil_varian_mnc_output[0]))
        options.registration = options.registration.replace(
            resolution=resolution)

        target_file = MincAtom(name=icoil_varian_mnc_output[0],
                               pipeline_sub_dir=target_dir)
        targets = RegistrationTargets(registration_standard=target_file,
                                      xfm_to_standard=None,
                                      registration_native=None)

        lsq6_result = s.defer(
            lsq6_nuc_inorm(imgs=icoil_imgs,
                           resolution=resolution,
                           registration_targets=targets,
                           lsq6_dir=lsq6_dir,
                           lsq6_options=options.saddle_recon.lsq6))
        all_lsq6_results.append(lsq6_result)

        ###########################
        # Step 3: distortion correct lsq6 output image
        ###########################
        lsq6_file = MincAtom(os.path.join(lsq6_dir, "average.mnc"),
                             pipeline_sub_dir=lsq6_dir)
        dc_lsq6_file = MincAtom(os.path.join(lsq6_dir,
                                             "average.aug2015_dist_corr.mnc"),
                                pipeline_sub_dir=lsq6_dir)
        dc_result = s.defer(
            dist_corr_saddle(img=lsq6_file, dc_img=dc_lsq6_file))
        all_dc_results.append(dc_result)

        ###########################
        # Step 4: crop distortion corrected lsq6 output image
        ###########################
        cropped_dc_lsq6_file = MincAtom(os.path.join(
            lsq6_dir, "average.aug2015_dist_corr.cropped.mnc"),
                                        pipeline_sub_dir=lsq6_dir)
        crop_result = s.defer(
            crop_to_brain(
                img=dc_lsq6_file,
                cropped_img=cropped_dc_lsq6_file,
                crop_to_brain_options=options.saddle_recon.crop_to_brain))
        all_crop_results.append(crop_result)

    return Result(stages=s,
                  output=Namespace(varian_output=varian_recon_results,
                                   lsq6_output=all_lsq6_results,
                                   dc_output=all_dc_results,
                                   crop_output=all_crop_results))
コード例 #16
0
def mbm(imgs: List[MincAtom],
        options: MBMConf,
        prefix: str,
        output_dir: str = "",
        with_maget: bool = True):

    # TODO could also allow pluggable pipeline parts e.g. LSQ6 could be substituted out for the modified LSQ6
    # for the kidney tips, etc...

    # TODO this is tedious and annoyingly similar to the registration chain ...
    lsq6_dir = os.path.join(output_dir, prefix + "_lsq6")
    lsq12_dir = os.path.join(output_dir, prefix + "_lsq12")
    nlin_dir = os.path.join(output_dir, prefix + "_nlin")

    s = Stages()

    if len(imgs) == 0:
        raise ValueError("Please, some files!")

    # FIXME: why do we have to call registration_targets *outside* of lsq6_nuc_inorm? is it just because of the extra
    # options required?  Also, shouldn't options.registration be a required input (as it contains `input_space`) ...?
    targets = s.defer(
        registration_targets(lsq6_conf=options.mbm.lsq6,
                             app_conf=options.application,
                             reg_conf=options.registration,
                             first_input_file=imgs[0].path))

    # TODO this is quite tedious and duplicates stuff in the registration chain ...
    resolution = (options.registration.resolution or get_resolution_from_file(
        targets.registration_standard.path))
    options.registration = options.registration.replace(resolution=resolution)

    # FIXME: this needs to go outside of the `mbm` function to avoid being run from within other pipelines (or
    # those other pipelines need to turn off this option)
    if with_maget:
        if options.mbm.segmentation.run_maget or options.mbm.maget.maget.mask:

            # temporary fix...?
            if options.mbm.maget.maget.mask and not options.mbm.segmentation.run_maget:
                # which means that --no-run-maget was specified
                if options.mbm.maget.maget.atlas_lib == None:
                    # clearly you do not want to run MAGeT at any point in this pipeline
                    err_msg_maget = "\nYou specified not to run MAGeT using the " \
                                    "--no-run-maget flag. However, the code also " \
                                    "wants to use MAGeT to generate masks for your " \
                                    "input files after the 6 parameter alignment (lsq6). " \
                                    "Because you did not specify a MAGeT atlas library " \
                                    "this can not be done. \nTo run the pipeline without " \
                                    "using MAGeT to mask your input files, please also " \
                                    "specify: \n--maget-no-mask\n"
                    raise ValueError(err_msg_maget)

            import copy
            maget_options = copy.deepcopy(options)  #Namespace(maget=options)
            #maget_options
            #maget_options.maget = maget_options.mbm
            #maget_options.execution = options.execution
            #maget_options.application = options.application
            #maget_options.application.output_directory = os.path.join(options.application.output_directory, "segmentation")
            maget_options.maget = options.mbm.maget

            fixup_maget_options(maget_options=maget_options.maget,
                                nlin_options=maget_options.mbm.nlin,
                                lsq12_options=maget_options.mbm.lsq12)
            del maget_options.mbm

        #def with_new_output_dir(img : MincAtom):
        #img = copy.copy(img)
        #img.pipeline_sub_dir = img.pipeline_sub_dir + img.output_dir
        #img.
        #return img.newname_with_suffix(suffix="", subdir="segmentation")

    # FIXME it probably makes most sense if the lsq6 module itself (even within lsq6_nuc_inorm) handles the run_lsq6
    # setting (via use of the identity transform) since then this doesn't have to be implemented for every pipeline
    if options.mbm.lsq6.run_lsq6:
        lsq6_result = s.defer(
            lsq6_nuc_inorm(imgs=imgs,
                           resolution=resolution,
                           registration_targets=targets,
                           lsq6_dir=lsq6_dir,
                           lsq6_options=options.mbm.lsq6))
    else:
        # FIXME the code shouldn't branch here based on run_lsq6 (which should probably
        # be part of the lsq6 options rather than the MBM ones; see comments on #287.
        # TODO don't actually do this resampling if not required (i.e., if the imgs already have the same grids)??
        # however, for now need to add the masks:
        identity_xfm = s.defer(
            param2xfm(
                out_xfm=FileAtom(name=os.path.join(lsq6_dir, 'tmp', "id.xfm"),
                                 pipeline_sub_dir=lsq6_dir,
                                 output_sub_dir='tmp')))
        lsq6_result = [
            XfmHandler(source=img,
                       target=img,
                       xfm=identity_xfm,
                       resampled=s.defer(
                           mincresample_new(img=img,
                                            like=targets.registration_standard,
                                            xfm=identity_xfm))) for img in imgs
        ]
    # what about running nuc/inorm without a linear registration step??

    if with_maget and options.mbm.maget.maget.mask:
        masking_imgs = copy.deepcopy([xfm.resampled for xfm in lsq6_result])
        masked_img = (s.defer(
            maget_mask(imgs=masking_imgs,
                       resolution=resolution,
                       maget_options=maget_options.maget,
                       pipeline_sub_dir=os.path.join(
                           options.application.output_directory,
                           "%s_atlases" % prefix))))

        masked_img.index = masked_img.apply(lambda x: x.path)

        # replace any masks of the resampled images with the newly created masks:
        for xfm in lsq6_result:
            xfm.resampled = masked_img.loc[xfm.resampled.path]
    elif with_maget:
        warnings.warn(
            "Not masking your images from atlas masks after LSQ6 alignment ... probably not what you want "
            "(this can have negative effects on your registration and statistics)"
        )

    #full_hierarchy = get_nonlinear_configuration_from_options(nlin_protocol=options.mbm.nlin.nlin_protocol,
    #                                                          flag_nlin_protocol=next(iter(options.mbm.nlin.flags_.nlin_protocol)),
    #                                                         reg_method=options.mbm.nlin.reg_method,
    #                                                          file_resolution=resolution)

    #I = TypeVar("I")
    #X = TypeVar("X")
    #def wrap_minc(nlin_module: NLIN[I, X]) -> type[NLIN[MincAtom, XfmAtom]]:
    #    class N(NLIN[MincAtom, XfmAtom]): pass

    # TODO now the user has to call get_nonlinear_component followed by parse_<...>; previously various things
    # like lsq12_nlin_pairwise all branched on the reg_method so one didn't have to call get_nonlinear_component;
    # they could still do this if it can be done safety (i.e., not breaking assumptions of various nonlinear units)
    nlin_module = get_nonlinear_component(
        reg_method=options.mbm.nlin.reg_method)

    nlin_build_model_component = get_model_building_procedure(
        options.mbm.nlin.reg_strategy,
        # was: model_building.reg_strategy
        reg_module=nlin_module)

    # does this belong here?
    # def model_building_with_initial_target_generation(prelim_model_building_component,
    #                                                   final_model_building_component):
    #     class C(final_model_building_component):
    #         @staticmethod
    #         def build_model(imgs,
    #                         conf     : BuildModelConf,
    #                         nlin_dir,
    #                         nlin_prefix,
    #                         initial_target,
    #                         output_name_wo_ext = None): pass
    #
    #     return C

    #if options.mbm.model_building.prelim_reg_strategy is not None:
    #    prelim_nlin_build_model_component = get_model_building_procedure(options.mbm.model_building.prelim_reg_strategy,
    #                                                                     reg_module=nlin_module)
    #    nlin_build_model_component = model_building_with_initial_target_generation(
    #                                   final_model_building_component=nlin_build_model_component,
    #                                   prelim_model_building_component=prelim_nlin_build_model_component)

    # TODO don't use name 'x_module' for something that's technically not a module ... perhaps unit/component?

    # TODO tedious: why can't parse_build_model_protocol handle the null protocol case? is this something we want?
    nlin_conf = (nlin_build_model_component.parse_build_model_protocol(
        options.mbm.nlin.nlin_protocol, resolution=resolution)
                 if options.mbm.nlin.nlin_protocol is not None else
                 nlin_build_model_component.get_default_build_model_conf(
                     resolution=resolution))

    lsq12_nlin_result = s.defer(
        lsq12_nlin_build_model(
            nlin_module=nlin_build_model_component,
            imgs=[xfm.resampled for xfm in lsq6_result],
            lsq12_dir=lsq12_dir,
            nlin_dir=nlin_dir,
            nlin_prefix=prefix,
            use_robust_averaging=options.mbm.nlin.use_robust_averaging,
            resolution=resolution,
            lsq12_conf=options.mbm.lsq12,
            nlin_conf=nlin_conf))  #options.mbm.nlin

    inverted_xfms = [
        s.defer(invert_xfmhandler(xfm)) for xfm in lsq12_nlin_result.output
    ]

    if options.mbm.stats.stats_kernels:
        determinants = s.defer(
            determinants_at_fwhms(xfms=inverted_xfms,
                                  inv_xfms=lsq12_nlin_result.output,
                                  blur_fwhms=options.mbm.stats.stats_kernels))
    else:
        determinants = None

    overall_xfms = [
        s.defer(concat_xfmhandlers([rigid_xfm, lsq12_nlin_xfm])) for rigid_xfm,
        lsq12_nlin_xfm in zip(lsq6_result, lsq12_nlin_result.output)
    ]

    output_xfms = (
        pd.DataFrame({
            "rigid_xfm":
            lsq6_result,  # maybe don't return this if LSQ6 not run??
            "lsq12_nlin_xfm": lsq12_nlin_result.output,
            "overall_xfm": overall_xfms
        }))
    # we could `merge` the determinants with this table, but preserving information would cause lots of duplication
    # of the transforms (or storing determinants in more columns, but iterating over dynamically known columns
    # seems a bit odd ...)

    # TODO transpose these fields?})
    #avg_img=lsq12_nlin_result.avg_img,  # inconsistent w/ WithAvgImgs[...]-style outputs
    # "determinants"    : determinants })

    #output.avg_img = lsq12_nlin_result.avg_img
    #output.determinants = determinants   # TODO temporary - remove once incorporated properly into `output` proper
    # TODO add more of lsq12_nlin_result?

    # FIXME moved above rest of registration for debugging ... shouldn't use and destructively modify lsq6_result!!!
    if with_maget and options.mbm.segmentation.run_maget:
        maget_options = copy.deepcopy(maget_options)
        maget_options.maget.maget.mask = maget_options.maget.maget.mask_only = False  # already done above
        # use the original masks here otherwise the masking step will be re-run due to the previous masking run's
        # masks having been applied to the input images:
        maget_result = s.defer(
            maget(
                [xfm.resampled for xfm in lsq6_result],
                #[xfm.resampled for _ix, xfm in mbm_result.xfms.rigid_xfm.iteritems()],
                options=maget_options,
                prefix="%s_MAGeT" % prefix,
                output_dir=os.path.join(output_dir, prefix + "_processed")))
        # FIXME add pipeline dir to path and uncomment!
        #maget.to_csv(path_or_buf="segmentations.csv", columns=['img', 'voted_labels'])

    # TODO return some MAGeT stuff from MBM function ??
    # if options.mbm.mbm.run_maget:
    #     import copy
    #     maget_options = copy.deepcopy(options)  #Namespace(maget=options)
    #     #maget_options
    #     #maget_options.maget = maget_options.mbm
    #     #maget_options.execution = options.execution
    #     #maget_options.application = options.application
    #     maget_options.maget = options.mbm.maget
    #     del maget_options.mbm
    #
    #     s.defer(maget([xfm.resampled for xfm in lsq6_result],
    #                   options=maget_options,
    #                   prefix="%s_MAGeT" % prefix,
    #                   output_dir=os.path.join(output_dir, prefix + "_processed")))

    # should also move outside `mbm` function ...
    #if options.mbm.thickness.run_thickness:
    #    if not options.mbm.segmentation.run_maget:
    #        warnings.warn("MAGeT files (atlases, protocols) are needed to run thickness calculation.")
    #    # run MAGeT to segment the nlin average:
    #    import copy
    #    maget_options = copy.deepcopy(options)  #Namespace(maget=options)
    #    maget_options.maget = options.mbm.maget
    #    del maget_options.mbm
    #    segmented_avg = s.defer(maget(imgs=[lsq12_nlin_result.avg_img],
    #                                  options=maget_options,
    #                                  output_dir=os.path.join(options.application.output_directory,
    #                                                          prefix + "_processed"),
    #                                  prefix="%s_thickness_MAGeT" % prefix)).ix[0].img
    #    thickness = s.defer(cortical_thickness(xfms=pd.Series(inverted_xfms), atlas=segmented_avg,
    #                                           label_mapping=FileAtom(options.mbm.thickness.label_mapping),
    #                                           atlas_fwhm=0.56, thickness_fwhm=0.56))  # TODO magic fwhms
    #    # TODO write CSV -- should `cortical_thickness` do this/return a table?

    output = Namespace(avg_img=lsq12_nlin_result.avg_img,
                       xfms=output_xfms,
                       determinants=determinants)

    if with_maget and options.mbm.segmentation.run_maget:
        output.maget_result = maget_result

        nlin_maget = (
            s.defer(
                maget(
                    [lsq12_nlin_result.avg_img],
                    #[xfm.resampled for _ix, xfm in mbm_result.xfms.rigid_xfm.iteritems()],
                    options=maget_options,
                    prefix="%s_nlin_MAGeT" % prefix,
                    output_dir=os.path.join(
                        output_dir,
                        prefix + "_processed")))).iloc[0]  #.voted_labels
        #output.avg_img.mask = nlin_maget.mask  # makes more sense, but might have weird effects elsewhere
        output.avg_img.labels = nlin_maget.labels

    return Result(stages=s, output=output)
コード例 #17
0
def f():
    return FileAtom('/path/to/a/file.ext')
コード例 #18
0
def tv_recon_pipeline(options):
    output_dir = options.application.output_directory
    pipeline_name = options.application.pipeline_name

    s = Stages()

    slices_df = pd.read_csv(options.application.csv_file,
                     dtype={"brain_name": str, "brain_directory": str, "slice_directory": str})

    if "qc" not in slices_df.columns:
        slices_df["qc"] = False
        step = int(1 / options.deep_segment.qc_fraction)
        slices_df.qc[0::step] = True

#############################
# Step 1: Run deep_segment.py
#############################
    #TODO surely theres a way around deep_segment_result=""?
    slices_df = slices_df.assign(
        deep_segment_result="",
        segmentation_directory = lambda df: df.apply(
            lambda row: os.path.join(output_dir, pipeline_name + "_deep_segmentation", row.brain_name), axis=1)
    )
    for index, row in slices_df.iterrows():
        slices_df.at[index,"deep_segment_result"] = s.defer(deep_segment(image = FileAtom(row.slice,
                                                                                          output_sub_dir = row.segmentation_directory),
                                                                         deep_segment_pipeline = FileAtom(options.deep_segment.deep_segment_pipeline),
                                                                         anatomical_suffix = options.deep_segment.anatomical_name,
                                                                         count_suffix = options.deep_segment.count_name,
                                                                         outline_suffix = options.deep_segment.outline_name if row.qc else None,
                                                                         cell_min_area = options.deep_segment.cell_min_area,
                                                                         cell_mean_area = options.deep_segment.cell_mean_area,
                                                                         cell_max_area = options.deep_segment.cell_max_area,
                                                                         temp_dir = options.deep_segment.temp_dir
                                                                         ))
        #hacky solution requires deep_segment() returns in that order
        #https://stackoverflow.com/questions/35491274/pandas-split-column-of-lists-into-multiple-columns
        slices_df[["anatomical_result", "count_result", "outline_result"]] = \
            pd.DataFrame(slices_df.deep_segment_result.values.tolist())

#############################
# Step 2: Run stacks_to_volume.py
#############################
    #This is annoying... If I add anything to slices_df, I will have to delete it here as well
    mincs_df = slices_df.drop(['slice', 'deep_segment_result', "anatomical_result", "count_result", "outline_result", "qc"], axis=1) \
        .drop_duplicates().reset_index(drop=True)\
        .assign(
        anatomical_list = slices_df.groupby("brain_name")['anatomical_result'].apply(list).reset_index(drop=True),
        count_list=slices_df.groupby("brain_name")['count_result'].apply(list).reset_index(drop=True),
        #the above is so hacky...
        stacked_directory=lambda df: df.apply(
            lambda row: os.path.join(output_dir, pipeline_name + "_stacked", row.brain_name), axis=1),
    )
    mincs_df = mincs_df.assign(
        anatomical_stacked_MincAtom=lambda df: df.apply(
            lambda row: MincAtom(
                os.path.join(row.stacked_directory,
                             row.brain_name + "_" + options.deep_segment.anatomical_name + "_stacked.mnc")
            ), axis=1
        ),
        count_stacked_MincAtom=lambda df: df.apply(
            lambda row: MincAtom(
                os.path.join(row.stacked_directory,
                             row.brain_name + "_" + options.deep_segment.count_name + "_stacked.mnc")
            ), axis=1
        )
    )
    if not options.stacks_to_volume.manual_scale_output:
        mincs_df["scale_output"] = mincs_df.interslice_distance/mincs_df.interslice_distance.min()

    for index, row in mincs_df.iterrows():
        s.defer(stacks_to_volume(
            slices = row.anatomical_list,
            output_volume = row.anatomical_stacked_MincAtom,
            z_resolution = row.interslice_distance,
            stacks_to_volume_options=options.stacks_to_volume,
            uniform_sum=False
        ))
        s.defer(stacks_to_volume(
            slices=row.count_list,
            output_volume=row.count_stacked_MincAtom,
            z_resolution=row.interslice_distance,
            stacks_to_volume_options=options.stacks_to_volume,
            scale_output = row.scale_output,
            uniform_sum=True
        ))
#############################
# Step 3: Run autocrop to resample to isotropic
#############################
    for index, row in mincs_df.iterrows():
        mincs_df.at[index,"anatomical_isotropic_result"] = s.defer(autocrop(
            img = row.anatomical_stacked_MincAtom,
            isostep = options.stacks_to_volume.plane_resolution,
            suffix = "isotropic"
        ))
        mincs_df.at[index, "count_isotropic_result"] = s.defer(autocrop(
            img=row.count_stacked_MincAtom,
            isostep=options.stacks_to_volume.plane_resolution,
            suffix="isotropic",
            nearest_neighbour = True
        ))

#############################
    slices_df = slices_df.assign(
        anatomical_slice = lambda df: df.apply(lambda row: row.anatomical_result.path, axis=1),
        count_slice=lambda df: df.apply(lambda row: row.count_result.path, axis=1),
        outline_slice=lambda df: df.apply(lambda row: row.outline_result.path if row.outline_result else None, axis=1),
    )
    slices_df.drop(slices_df.filter(regex='.*_directory.*|.*_result.*'), axis=1)\
        .to_csv("TV_processed_slices.csv", index=False)

    mincs_df = mincs_df.assign(
        anatomical=lambda df: df.apply(lambda row: row.anatomical_isotropic_result.path, axis=1),
        count=lambda df: df.apply(lambda row: row.count_isotropic_result.path, axis=1),
    )
    mincs_df.drop(mincs_df.filter(regex='.*_result.*|.*_list.*|.*_MincAtom.*'), axis=1)\
        .to_csv("TV_mincs.csv", index=False)
    #TODO overlay them
    # s.defer(create_quality_control_images(imgs=reconstructed_mincs, montage_dir = output_dir,
    #     montage_output=os.path.join(output_dir, pipeline_name + "_stacked", "reconstructed_montage"),
    #                                       message="reconstructed_mincs"))

    #TODO
    # s.defer(create_quality_control_images(imgs=all_anatomical_pad_results, montage_dir=output_dir,
    #                                       montage_output=os.path.join(output_dir, pipeline_name + "_stacked",
    #                                                                   "%s_montage" % anatomical),
    #                                       message="%s_mincs" % anatomical))
    # s.defer(create_quality_control_images(imgs=all_count_pad_results, montage_dir=output_dir,
    #                                       montage_output=os.path.join(output_dir, pipeline_name + "_stacked",
    #                                                                   "%s_montage" % count),
    #                                       auto_range=True,
    #                                       message="%s_mincs" % count))
    return Result(stages=s, output=())
コード例 #19
0
ファイル: thickness.py プロジェクト: psteadman/pydpiper
def transform_objects(input_obj : FileAtom,
                      xfm       : XfmAtom) -> Result[FileAtom]:  # XfmAtom -> XfmHandler??
    output_obj = input_obj.newname_with_suffix("_resampled_via_%s" % xfm.filename_wo_ext)
    stage = CmdStage(inputs=(input_obj, xfm), outputs=(output_obj,),
                     cmd=["transform_objects", input_obj.path, xfm.path, output_obj.path])
    return Result(stages=Stages([stage]), output=output_obj)