def shift_modify_header(img: MincAtom, shifted_img: MincAtom, newx: float, newy: float, newz: float): s = Stages() #Copy file to new location stage = CmdStage(inputs=(img,), outputs=(shifted_img,), memory=1, cmd=['cp', img.path, shifted_img.path]) print(stage.render()) s.add(stage) #Alter header of copied image to shift xspace_start = 'xspace:start='+newx yspace_start = 'yspace:start='+newy zspace_start = 'zspace:start='+newz stage = CmdStage(inputs=(shifted_img,), outputs=(shifted_img,), memory=1, cmd=['minc_modify_header','-dinsert',xspace_start, '-dinsert',yspace_start, '-dinsert',zspace_start, shifted_img.path]) print(stage.render()) s.add(stage) #Alter header of copied image with header modification append_history_string = ':history= >>> copy and shift: '+ shifted_img.path +' to '+ shifted_img.path stage = CmdStage(inputs=(shifted_img,), outputs=(shifted_img,), memory=1, cmd=['minc_modify_header','-sappend', append_history_string, shifted_img.path]) print(stage.render()) s.add(stage) return Result(stages=s, output=shifted_img)
def dist_corr_basket(img: MincAtom, dc_img: MincAtom): stage = CmdStage(inputs=(img,), outputs=(dc_img,), memory=4, cmd=['distortion_correction_september_2014.pl', '-spawn','-output-dir', img.pipeline_sub_dir, img.path]) print(stage.render()) stage.set_log_file(log_file_name=os.path.join(img.pipeline_sub_dir,"dist_corr.log")) return Result(stages=Stages([stage]), output=dc_img)
def dramms_warp_simple(img: NiiAtom, xfm: DrammsXfmAtom, like: Optional[NiiAtom] = None, extra_flags: Tuple[str] = (), use_nn_interpolation=None, invert: bool = False, new_name_wo_ext: str = None, subdir: str = None) -> Result[NiiAtom]: """ Resample an image, ignoring mask/labels ... new_name_wo_ext -- string indicating a user specified file name (without extension) """ s = Stages() if invert: inv_xfm = xfm.newname_with_suffix("_inverted") s.add( CmdStage(cmd=["dramms-defop", "-i", xfm.path, inv_xfm.path], inputs=(xfm, ), outputs=(inv_xfm, ))) xfm = inv_xfm if not subdir: subdir = 'resampled' if not new_name_wo_ext: # FIXME the path to `outf` is wrong. For instance, resampling a mask file ends up in the initial model # FIXME directory instead of in the resampled directory. # FIXME At the same time, `like.newname(...)` doesn't work either, for similar reasons. # FIXME Not clear if there's a general "automagic" fix for this. # FIXME Also, using the xfm's filename is wrong, since we might be resampling, e.g., a mask. # FIXME We should basically use the same naming scheme as is used to generate the xfm's name but # FIXME use the files for resampling, not registration outf = img.newname(name=xfm.filename_wo_ext + '-resampled', subdir=subdir) else: # we have the output filename without extension. This should replace the entire # current "base" of the filename. outf = img.newname(name=new_name_wo_ext, subdir=subdir) stage = CmdStage( inputs=(xfm, like, img), outputs=(outf, ), cmd=(['dramms-warp'] + (['-n'] if use_nn_interpolation else []) + (['-transform %s' % xfm.path]) #if xfm is not identity else []) + ['-like %s' % like.path, img.path, outf.path])) s.add(stage) return Result(stages=s, output=outf)
def antsRegistration(fixed: MincAtom, moving: MincAtom, transform: XfmAtom, output_dir: str, warped: str = "Warped.nii.gz", inversewarped: str = "InverseWarped.nii.gz", dimensionality: int = 3): #TODO warped and inversewarped output to the working directory stage = CmdStage( inputs=(fixed, moving), outputs=(transform, ), cmd=[ 'antsRegistration', '--verbose 1', '--float 0', '--minc', '--dimensionality %s' % dimensionality, '--output [%s,%s,%s]' % (transform.path.replace( '0_GenericAffine.xfm', ''), warped, inversewarped), '--interpolation Linear', '--use-histogram-matching 0', '--winsorize-image-intensities [0.01,0.99]', '--initial-moving-transform [%s,%s,1]' % (fixed.path, moving.path), #1 indicates center of mass '--transform Translation[0.1]', '--metric MI[%s,%s,1,32,Regular,0.25]' % (fixed.path, moving.path), '--convergence [1000x500x250x0,1e-6,10]', '--shrink-factors 12x8x4x2', '--smoothing-sigmas 4x3x2x1vox' ], log_file=os.path.join(output_dir, "join_sections.log")) return Result(stages=Stages([stage]), output=(transform))
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))
def blur(img, fwhm, gradient=True, subdir='tmp'): # note c3d can take voxel rather than fwhm specification, but the Algorithms interface # currently doesn't allow this to be used ... maybe an argument from switching from mincblur if fwhm in (-1, 0, None): if gradient: raise ValueError( "can't compute gradient without a positive FWHM") return Result(stages=Stages(), output=Namespace(img=img)) if gradient: out_gradient = img.newname_with("_blur%s_grad" % fwhm) else: out_gradient = None out_img = img.newname_with("_blurred%s" % fwhm) cmd = CmdStage(cmd=[ 'c3d', '-smooth', "%smm" % fwhm, '-o', out_img.path, img.path ] + (['-gradient', '-o', out_gradient.path] if gradient else []), inputs=(img), outputs=(out_img, out_gradient) if gradient else (out_img, )) return Result(stages=Stages((cmd, )), output=Namespace(img=out_img, gradient=out_gradient) if gradient else Namespace(img=out_img))
def crop_to_brain(img: MincAtom, cropped_img: MincAtom, crop_to_brain_options): stage = CmdStage(inputs=(img,), outputs=(cropped_img,), memory=4, cmd=['crop_to_brain.py', '--bbox_x',str(crop_to_brain_options.bbox_x), '--bbox_y',str(crop_to_brain_options.bbox_y), '--bbox_z',str(crop_to_brain_options.bbox_z), '--intermediate_bbox=1.5', '--buffer_z',str(crop_to_brain_options.buffer_z), '--clobber', img.path, cropped_img.path]) print(stage.render()) stage.set_log_file(log_file_name=os.path.join(img.pipeline_sub_dir,"crop_to_brain.log")) return Result(stages=Stages([stage]), output=cropped_img)
def as_deformation(xfm): c = CmdStage(cmd=[ "transformix", "-def", "all", "-out", dirname, "-tp", xfm.path, "-xfm", out_path ], inputs=(xfm, ), outputs=NotImplemented) return Result(stages=Stages([c]), output=NotImplemented)
def scale_transform(xfm, scale, newname_wo_ext): scaled_xfm = xfm.newname_with_suffix("_scaled%s" % scale) c = CmdStage( cmd=["dramms-defop", "-m", str(scale), xfm.path, scaled_xfm.path], inputs=(xfm, ), outputs=(scaled_xfm, )) return Result(stages=Stages([c]), output=scaled_xfm)
def smooth_vector(source: MincAtom, fwhm: float) -> Result[MincAtom]: outf = source.newname_with_suffix( "_smooth_fwhm%s" % fwhm, subdir="tmp") # TODO smooth_displacement_? cmd = [ 'smooth_vector', '--clobber', '--filter', '--fwhm=%s' % fwhm, source.path, outf.path ] stage = CmdStage(inputs=(source, ), outputs=(outf, ), cmd=cmd) return Result(stages=Stages([stage]), output=outf)
def set_params(stage: CmdStage): img_pyminc = pyminc.volumeFromFile(img.path) ref_pyminc = pyminc.volumeFromFile(ref.path) count = np.maximum(ref_pyminc.data.count, img_pyminc.data.count) sum = ref_pyminc.data.count[0] + img_pyminc.data.count[0] for index, arg in enumerate(stage.cmd): stage.cmd[index] = arg.format(start='0,0,0,', count='%s,%s,%s' % (sum, count[1], count[2]))
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)
def register( source: MincAtom, target: MincAtom, conf: Conf, initial_source_transform: Optional[XfmAtom] = None, transform_name_wo_ext: str = None, generation: int = None, # not used; remove from API (fix ANTS) resample_source: bool = False, resample_subdir: str = "resampled") -> Result[XfmHandler]: if conf is None: raise ValueError("no configuration supplied") out_dir = os.path.join( source.pipeline_sub_dir, source.output_sub_dir, "%s_elastix_to_%s" % (source.filename_wo_ext, target.filename_wo_ext)) # elastix chooses this for us: out_img = NiiAtom( name=os.path.join(out_dir, "result.%d.mnc" % 0), # TODO number of param files ?!?! pipeline_sub_dir=source.pipeline_sub_dir, output_sub_dir=source.output_sub_dir) #out_xfm = XfmAtom(name = "%s_elastix_to_%s.xfm" % (source.filename_wo_ext, target.filename_wo_ext), # pipeline_sub_dir=source.pipeline_sub_dir, output_sub_dir=source.output_sub_dir) out_xfm = XfmAtom( name=os.path.join(out_dir, "TransformParameters.%d.txt" % 0), # TODO number of param files ?!?! pipeline_sub_dir=source.pipeline_sub_dir, output_sub_dir=source.output_sub_dir) cmd = (['elastix', '-f', source.path, '-m', target.path] + (flatten(*[["-p", x] for x in conf])) + (["-fMask", source.mask.path] if source.mask else []) + (["-mMask", target.mask.path] if target.mask else []) + (["-t0", initial_source_transform.path] if initial_source_transform else []) + (["-out", out_dir])) s = CmdStage(cmd=cmd, inputs=(source, target) + ((source.mask, ) if source.mask else ()) + ((target.mask, ) if target.mask else ()), outputs=(out_xfm, out_img)) #s2 = CmdStage(cmd=['transformix', '-out', os.path.join(resample_subdir, "%s" % c), # "-tp", out_xfm, "-in", out_name], # inputs=(), outputs=()) xfm = XfmHandler(source=source, target=target, xfm=out_xfm, resampled=out_img) return Result(stages=Stages([s]), output=xfm) # one question is whether we should have separate NLIN/LSQ12/LSQ6 interfaces or not, given that these differences seem # like they should be rather irrelevant to general registration procedures ... at present minctracc # is the main difficulty, since it uses different
def concat_xfm(xfms: List[XfmAtom], outxfm: XfmAtom, output_dir: str): stage = CmdStage(inputs=tuple(xfms), outputs=(outxfm, ), cmd=[ 'xfmconcat', '-clobber', ' '.join(xfm.path for xfm in xfms.__iter__()), outxfm.path ], log_file=os.path.join(output_dir, "join_sections.log")) return Result(stages=Stages([stage]), output=(outxfm))
def dramms_invert(defs: DrammsXfmAtom, out_defs: Optional[DrammsXfmAtom] = None): out_defs = out_defs or defs.newname_with_suffix("_inverted") return Result(stages=Stages([ CmdStage(cmd=['dramms-defop', '-i', defs.path, out_defs.path], inputs=(defs, ), outputs=(out_defs, )) ]), output=out_defs)
def itk_convert_xfm(xfm: ITKXfmAtom, out_ext: str) -> Result[ITKXfmAtom]: if xfm.ext == out_ext: return Result(stages=Stages(), output=xfm) else: out_xfm = xfm.newext(out_ext) cmd = CmdStage( inputs=(xfm, ), outputs=(out_xfm, ), cmd=["itk_convert_xfm", "--clobber", xfm.path, out_xfm.path]) return Result(stages=Stages((cmd, )), output=out_xfm)
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)
def reconstitute_laplacian_grid(cortex: MincAtom, grid: MincAtom, midline: MincAtom) -> Result[MincAtom]: output_grid = grid.newname_with_suffix("_reconstituted") stage = CmdStage(inputs=(cortex, grid, midline), outputs=(output_grid, ), cmd=[ "reconstitute_laplacian_grid", midline.path, cortex.path, grid.path, output_grid.path ]) return Result(stages=Stages([stage]), output=output_grid)
def mincmath(imgs: List[MincAtom], result: MincAtom, output_dir: str): stage = CmdStage(inputs=tuple(imgs), outputs=(result, ), cmd=[ 'mincmath', '-clobber', '-add', ' '.join(img.path for img in imgs.__iter__()), result.path ], log_file=os.path.join(output_dir, "join_sections.log")) return Result(stages=Stages([stage]), output=result)
def varian_recon_ge3dmice_saddle(fids: List[FileAtom], imgs: List[MincAtom], varian_recon_options, output_dir: str): stage = CmdStage(inputs=tuple(fids), outputs=tuple(imgs), memory=25, cmd=['mri_recon.py', 'ge3dmice_sg_cylA' , '--petable_ordered_pairs', '--grappa_coil_decouple', '--outputreps', '--phasedriftcorr', '--mouse_list',varian_recon_options.mouse_list, '--petable',varian_recon_options.petable, '--grappa_coil_groupings',varian_recon_options.grappa_coil_groupings, '--procpar_file_name', varian_recon_options.procpar_file_name, '--clobber', '--fermi_ellipse' if varian_recon_options.fermi_ellipse else '', varian_recon_options.fid_input_directory, os.path.join(output_dir,varian_recon_options.output_file_name)]) print(stage.render()) stage.set_log_file(log_file_name=os.path.join(output_dir,"varian_recon.log")) return Result(stages=Stages([stage]), output=imgs)
def dramms_combine(t1: DrammsXfmAtom, t2: DrammsXfmAtom, name: Optional[str] = None): # TODO this is a hack ... implement more sane naming (factor from xfmconcat?) out_xfm = t1.newname(name="concat_of_%s_and_%s" % (t1.filename_wo_ext, t2.filename_wo_ext), subdir="transforms") s = CmdStage(cmd=['dramms-combine', '-c', t1.path, t2.path, out_xfm.path], inputs=(t1, t2), outputs=(out_xfm)) return Result(stages=Stages([s]), output=out_xfm)
def itk_to_dramms(xfm: ITKXfmAtom) -> Result[DrammsXfmAtom]: out_xfm = xfm.newname_with_suffix("_dramms") return Result(stages=Stages([ CmdStage(cmd=[ 'dramms-convert', '-f', 'ITK', '-i', xfm.path, '-F', 'DRAMMS', '-o', out_xfm.path ], inputs=(xfm, ), outputs=(out_xfm, )) ]), output=out_xfm)
def convert(infile: ImgAtom, out_ext: str) -> Result[ImgAtom]: s = Stages() outfile = infile.newext(ext=out_ext) if infile.mask is not None: outfile.mask = s.defer(convert(infile.mask, out_ext=out_ext)) if infile.labels is not None: outfile.mask = s.defer(convert(infile.labels, out_ext=out_ext)) s.add( CmdStage(inputs=(infile, ), outputs=(outfile, ), cmd=['c3d', infile.path, '-o', outfile.path])) return Result(stages=s, output=outfile)
def average_images( imgs: Sequence[ImgAtom], dimensions: int = 3, normalize: bool = False, output_dir: str = '.', name_wo_ext: str = "average", out_ext: Optional[str] = None, avg_file: Optional[ITKImgAtom] = None) -> Result[ITKImgAtom]: s = Stages() if len(imgs) == 0: raise ValueError( "`AverageImages` arg `imgs` is empty (can't average zero files)") ext = out_ext or imgs[0].ext # the output_dir basically gives us the equivalent of the pipeline_sub_dir for # regular input files to a pipeline, so use that here avg = avg_file or ImgAtom(name=os.path.join(output_dir, '%s.todo' % name_wo_ext), orig_name=None, pipeline_sub_dir=output_dir) avg.ext = ext # if all input files have masks associated with them, add the combined mask to # the average: # TODO what if avg_file has a mask ... should that be used instead? (then rename avg -> avg_file above) all_inputs_have_masks = all((img.mask for img in imgs)) if all_inputs_have_masks: combined_mask = (ImgAtom(name=os.path.join( avg_file.dir, '%s_mask.todo' % avg_file.filename_wo_ext), orig_name=None, pipeline_sub_dir=avg_file.pipeline_sub_dir) if avg_file is not None else ImgAtom( name=os.path.join(output_dir, '%s_mask.todo' % name_wo_ext), orig_name=None, pipeline_sub_dir=output_dir)) combined_mask.ext = ext s.defer( max(imgs=sorted({img_inst.mask for img_inst in imgs}), out_img=combined_mask)) avg.mask = combined_mask s.add( CmdStage( inputs=imgs, outputs=(avg, ), cmd=["AverageImages", str(dimensions), avg.path, "%d" % normalize] + [img.path for img in imgs])) return Result(stages=s, output=avg)
def average_transforms(xfms, avg_xfm): intermediate_xfm = avg_xfm.newname_with_suffix("_inter", subdir="tmp") s = Stages() s.add( CmdStage(cmd=[ "echo", ('(Transform "WeightedCombinationTransform")\n' '(SubTransforms %s)\n' '(NormalizeCombinationsWeights "true")\n') % ' '.join(sorted(xfm.path for xfm in xfms)) ], inputs=xfms, outputs=(intermediate_xfm, ))) s.add( CmdStage(cmd=[ "transformix", "-def", "all", "-out", os.path.dirname(avg_xfm.path), "-tp", intermediate_xfm.path, "-xfm", avg_xfm.path ], inputs=(intermediate_xfm, ), outputs=(avg_xfm, )))
def scale_transform(xfm, scale): scaled_xfm = xfm.newname_with_suffix("_scaled_%s" % scale) # don't actually evaluate the resulting vector field: s = CmdStage(cmd=[ "echo", ('(Transform "WeightedCombinationTransform")\n' '(SubTransforms %s)\n' '(Scales %s)\n') % (xfm.path, scale) ], inputs=(xfm, ), outputs=(scaled_xfm, )) return Result(stages=Stages([s]), output=scaled_xfm)
def scale_transform(xfm, scale, newname_wo_ext): s = Stages() defs = s.defer(as_deformation(transform=xfm.xfm, reference=xfm.source)) scaled_defs = (defs.xfm.newname(newname_wo_ext) if newname_wo_ext else defs.xfm.newname_with_suffix("_scaled_%s" % scale)) s.defer( CmdStage(cmd=[ 'c3d', '-scale', str(scale), defs.path, "-o", scaled_defs.path ], inputs=(defs, ), outputs=(scaled_defs, ))) return Result(stages=s, output=scaled_defs)
def lin_from_nlin(xfm: XfmHandler) -> Result[XfmHandler]: # TODO add dir argument out_xfm = xfm.xfm.newname_with_suffix("_linear_part", subdir="tmp") stage = CmdStage( inputs=(xfm.source, xfm.xfm), outputs=(out_xfm, ), cmd=(['lin_from_nlin', '-clobber', '-lsq12'] + (['-mask', xfm.source.mask.path] if xfm.source.mask else []) + [xfm.target.path, xfm.xfm.path, out_xfm.path])) return Result(stages=Stages([stage]), output=XfmHandler(xfm=out_xfm, source=xfm.source, target=xfm.target))
def to_mni_xfm(xfm): s = Stages() defs = xfm.newname_with_suffix("_defs", subdir="tmp") s.add( CmdStage(cmd=[ "transformix", "-def", "all", "-out", defs.dir, "-tp", xfm.path, "-xfm", os.path.join(defs.filename_wo_ext, defs.ext) ], inputs=(xfm, ), outputs=(defs, ))) out_xfm = s.defer(itk.itk_convert_xfm(defs, out_ext=".mnc")) return Result(stages=s, output=out_xfm)
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))