Source code for omni.pipelines.anat.align

import os
import shutil
import logging
import nibabel as nib
from memori.pathman import append_suffix, get_path_and_prefix, repath
from memori.helpers import create_output_path, create_symlink_to_path
from omni.affine import deoblique
from omni.interfaces.afni import Allineate, cat_matvec
from omni.interfaces.fsl import flirt
from omni.interfaces.common import run_process
from omni.io import convert_affine_file


# Directory this file lives in
THISDIR = os.path.dirname(os.path.abspath(__file__))

# Get atlas directory
ATLASDIR = os.path.join(os.path.dirname(THISDIR), "atlas")


[docs]@create_output_path def deoblique_anat(output_path: str, t1: str = None, t2: str = None): """Deoblique images. Parameters ---------- output_path : str Output path to write out files to. t1 : str T1 image. t2 : str T2 image. Returns ------- str T1 deobliqued. str T2 deobliqued. """ logging.info("Deobliquing anatomical images...") # Deoblique t1 if t1: t1_img = nib.load(t1) t1_do_img = deoblique(t1_img) t1_do = append_suffix(repath(output_path, t1), "_deobliqued") t1_do_img.to_filename(t1_do) else: t1_do = None # Deoblique t2 if t2: t2_img = nib.load(t2) t2_do_img = deoblique(t2_img) t2_do = append_suffix(repath(output_path, t2), "_deobliqued") t2_do_img.to_filename(t2_do) else: t2_do = None # return images return (t1_do, t2_do)
[docs]@create_output_path def align_anat( output_path: str, t1_debias: str, t2_debias: str, ref: str = "T1", program: str = "fsl", other_args: str = None ): """Align T1/T2 images. Parameters ---------- output_path : str Output path to write out files to. t1_debias : str Debiased T1 image. t2_debias : str Debiased T2 image. ref : str Set the image to use as a reference [T1/T2]. program : str Program to use for alignment ('afni': AFNI 3dAllineate or 'fsl': fsl flirt). other_args : str Other arguments to pass to alignment program. Returns ------- str Anatomical aligned T1 (aligned to ref) str Anatomical aligned T2 (aligned to ref). str Affine aligning T1/T2 (depends on what ref was set to). """ # set the reference and source images to use logging.info("Using %s as reference image for " "T1/T2 anatomical alignment.", ref) if ref == "T1": reference_img = t1_debias source_img = t2_debias anat_align_affine = os.path.join(output_path, "t2_to_t1_xfm.aff12.1D") t1_anat = append_suffix(repath(output_path, t1_debias), "_t1space") t2_anat = append_suffix(repath(output_path, t2_debias), "_t1space") anat_align_img = t2_anat elif ref == "T2": reference_img = t2_debias source_img = t1_debias anat_align_affine = os.path.join(output_path, "t1_to_t2_xfm.aff12.1D") t2_anat = append_suffix(repath(output_path, t2_debias), "_t2space") t1_anat = append_suffix(repath(output_path, t1_debias), "_t2space") anat_align_img = t1_anat else: raise ValueError("Invalid parameters set for ref. " "Must be either 'T1' or 'T2'.") # generate edge images def edge(prefix: str, in_file: str) -> None: return run_process(f"3dedge3 -prefix {prefix} -input {in_file} -verbose -overwrite") reference_edge_img = repath(output_path, append_suffix(reference_img, "_edge")) source_edge_img = repath(output_path, append_suffix(source_img, "_edge")) edge(reference_edge_img, reference_img) edge(source_edge_img, source_img) anat_align_edge_img = append_suffix(anat_align_img, "_edge") # align t1/t2 logging.info("Aligning anatomical images...") if program == "afni": # Use 3dAllineate # align edge images Allineate( anat_align_edge_img, reference_edge_img, source_edge_img, matrix_save=anat_align_affine, warp="shift_rotate", cost="mi", fineblur=4, nmatch="100%", twopass=True, other_args=other_args, ) # apply affine to anat image Allineate( anat_align_img, reference_img, source_img, matrix_apply=anat_align_affine, ) elif program == "fsl": # Use flirt # align edge images anat_align_fsl_affine = get_path_and_prefix(anat_align_affine) + ".mat" flirt( anat_align_edge_img, reference_edge_img, source_edge_img, out_matrix=anat_align_fsl_affine, dof=6, other_args=other_args, ) # apply affine to anat image flirt(anat_align_img, reference_img, source_img, other_args=f"-applyxfm -init {anat_align_fsl_affine}") # convert the fsl affine to afni convert_affine_file(anat_align_affine, anat_align_fsl_affine, "afni", target=reference_img, source=source_img) else: raise ValueError("Invalid parameter set for program. " "Must be either 'afni' or 'fsl'.") # add symlinks to ref image if ref == "T1": # symlink to debias and rename t1_debias_symlink = create_symlink_to_path(t1_debias, output_path) shutil.move(t1_debias_symlink, t1_anat) elif ref == "T2": # symlink to debias and rename t2_debias_symlink = create_symlink_to_path(t2_debias, output_path) shutil.move(t2_debias_symlink, t2_anat) # return file paths return (t1_anat, t2_anat, anat_align_affine)
[docs]@create_output_path def align_atlas( output_path: str, t1_debias: str, t2_debias: str, t1_debias_bet: str, t2_debias_bet: str, anat_align_affine: str, atlas: str = "mni", atlas_label: str = "atlas", ref: str = "T1", program: str = "fsl", other_args: str = None, ): """Align T1/T2 images to atlas. Parameters ---------- output_path : str Output path to write out files to. t1_debias : str Debiased T1 image. t2_debias : str Debiased T2 image. t1_debias_bet : str Debiased bet T1 image. t2_debias_bet : str Debiased bet T2 image. anat_align_affine : str Anatomical image to atlas. atlas : str Atlas to align to. atlas_label : str Label suffix for atlas outputs ref : str Set anatomical reference image that was used. program : str Program to use for alignment ('afni': AFNI 3dAllineate or 'fsl': fsl flirt). other_args : str Other arguments to pass to alignment program. Returns ------- str Atlas aligned T1. str Atlas aligned T2. """ # get atlas img if atlas == "mni": atlas_img = os.path.join(ATLASDIR, "mni_icbm152_t1_tal_nlin_sym_09c_bet.nii.gz") elif atlas == "trio": atlas_img = os.path.join(ATLASDIR, "TRIO_Y_NDC_bet.nii.gz") elif os.path.isfile(atlas): # Test if the atlas is a valid image file. nib.load(atlas) atlas_img = atlas atlas = atlas_label else: raise ValueError("Invalid atlas.") # create atlas aligned T1/T2 names t1_atlas_bet = append_suffix(repath(output_path, t1_debias_bet), "_" + atlas) atlas_align_affine = os.path.join(output_path, "atlas_align_affine.aff12.1D") # align T1 to mni atlas logging.info("Aligning anatomical images to atlas...") if program == "afni": Allineate( t1_atlas_bet, atlas_img, t1_debias_bet, warp="shift_rotate_scale", matrix_save=atlas_align_affine, cost="mi", fineblur=4, nmatch="100%", twopass=True, other_args=other_args, ) elif program == "fsl": atlas_align_fsl_affine = get_path_and_prefix(atlas_align_affine) + ".mat" flirt( t1_atlas_bet, atlas_img, t1_debias_bet, out_matrix=atlas_align_fsl_affine, dof=9, cost="mutualinfo", other_args=other_args, ) # convert the fsl affine to afni convert_affine_file(atlas_align_affine, atlas_align_fsl_affine, "afni", target=atlas_img, source=t1_debias_bet) else: raise ValueError("Invalid parameter set for program. " "Must be either 'afni' or 'fsl'.") # concatenate the affines transform concatenated_affine = os.path.join(output_path, "atlas_anat_align_affine.aff12.1D") cat_matvec(concatenated_affine, "{0} {1}".format(atlas_align_affine, anat_align_affine)) # apply affine to T1/T2 to transform to affine t1_atlas = append_suffix(repath(output_path, t1_debias), "_" + atlas) t2_atlas = append_suffix(repath(output_path, t2_debias), "_" + atlas) if ref == "T1": t1_atlas_affine = atlas_align_affine t2_atlas_affine = concatenated_affine elif ref == "T2": t1_atlas_affine = concatenated_affine t2_atlas_affine = atlas_align_affine else: raise ValueError("Invalid ref.") Allineate(t1_atlas, atlas_img, t1_debias, matrix_apply=t1_atlas_affine) Allineate(t2_atlas, atlas_img, t2_debias, matrix_apply=t2_atlas_affine) # return T1/T2 atlas aligned images return (t1_atlas, t2_atlas, atlas_align_affine)