Source code for omni.io

"""Read/write functions for various omni outputs.
"""
import os
from typing import Tuple
import numpy as np
import nibabel as nib
from .affine import convert_affine, afni_affine_to_rigid_body


[docs]def load_target_source(target: str, source: str) -> Tuple[nib.Nifti1Image, nib.Nifti1Image]: """Conveinence function for loading two images (target/source).""" t = nib.load(target) s = nib.load(source) return t, s
[docs]def load_interaction_spec(model: str) -> str: """Parse the interaction model input.""" # read in the *.model file if defined if ".model" in model: with open(model, "r") as f: spec = "".join([line.rstrip() for line in f.readlines()]) else: # else just return the model as text spec = model return spec
[docs]def read_omni_affine(filename: str) -> np.ndarray: """Read omni format affine matrix from disk.""" # load affine data with open(filename, "r") as f: data = np.loadtxt(f) return data
[docs]def read_afni_affine(filename: str) -> np.ndarray: """Loads the afni affine matrix file.""" with open(filename, "r") as f: lines = f.readlines() # remove comments from read lines lines = [i for i in lines if "#" not in i] # there should only be one entry in the lines now (make assertion check) assert ( len(lines) == 1 ), "There was an error in parsing the afni affine \ file. Tell Andrew that his parsing logic was wrong :(" # grab the first entry in lines for the affine matrix lines = [float(i) for i in lines[0].rstrip().split(" ") if i != ""] + [0, 0, 0, 1] # return matrix return np.array(lines).reshape(4, 4)
[docs]def read_afni_framewise_affine(filename: str) -> np.ndarray: """Loads in a framewise affine from afni Parameters ---------- filename: str Multi frame affine file to load. Returns ------- np.ndarray n x 16 array of affines """ with open(filename, "r") as f: lines = f.readlines() # remove comments from read lines lines = [i for i in lines if "#" not in i] # format string to floats lines = [[float(i) for i in line.rstrip().split(" ") if i != ""] + [0, 0, 0, 1] for line in lines] # return affine list return np.array(lines)
[docs]def convert_framewise_affine_to_rigid_body(output: str, filename: str) -> None: """Converts framewise affine file to rigid body. Parameters ---------- output: str Path/name of output rigid body parames file. filename: str Affine file to convert. """ # read in file affines = read_afni_framewise_affine(filename) # convert to rigid body params rigid_body_params = afni_affine_to_rigid_body(affines) # write the rigid body params to file np.savetxt( output, rigid_body_params, fmt="%.6f", header="3dAllineate parameters:\nx-shift y-shift z-shift z-angle x-angle y-angle", )
[docs]def read_affine_file(filename: str) -> Tuple[np.ndarray, str]: """Loads affine file from disk. Parameters ---------- filename: str Affine filename to load. Returns ------- np.ndarray 4x4 affine matrix. str Type of affine file loaded (omni/afni/fsl). """ # check extension of file to use appropriate loader _, ext = os.path.splitext(filename) if ext == ".affine": # omni return read_omni_affine(filename), "omni" elif ext == ".1D": # afni return read_afni_affine(filename), "afni" elif ext == ".mat": # fsl (file format is same as omni) return read_omni_affine(filename), "fsl" else: # Unknown extension raise ValueError("Unknown extension")
[docs]def write_omni_affine(filename: str, affine_mat: np.ndarray) -> None: """Writes omni format affine matrix to disk.""" # add extension if not exist _, ext = os.path.splitext(filename) if ext != ".affine": filename += ".affine" # write data to file with open(filename, "w") as f: np.savetxt(f, affine_mat)
[docs]def write_afni_affine(filename: str, affine_mat: np.ndarray) -> None: """Writes an afni affine matrix file to disk.""" # grab extension def get_ext(x): return "".join( [get_ext(os.path.splitext(x)[0]) if os.path.splitext(x)[1] != "" else "", os.path.splitext(x)[1]] ) # add extension if not exist ext = get_ext(filename) if ext != ".aff12.1D": filename += ".aff12.1D" # write data with open(filename, "w") as f: f.write("# 3dAllineate matrices (DICOM-to-DICOM, row-by-row):\n") f.write(" ") for i in affine_mat.ravel()[:12]: f.write(str(i)) f.write(" ")
[docs]def write_fsl_affine(filename: str, affine_mat: np.ndarray) -> None: """Writes fsl format affine matrix to disk.""" # add extension if not exist _, ext = os.path.splitext(filename) if ext != ".mat": filename += ".mat" # write data to file with open(filename, "w") as f: np.savetxt(f, affine_mat)
[docs]def write_affine_file(filename: str, affine_mat: np.ndarray, atype: str) -> None: """Write affine file. Parameters ---------- filename: str Filename of affine file to write. affine_mat: np.ndarray 4x4 affine matrix. atype: str Type of affine file to write (omni/afni/fsl). """ # call appropriate file writer if atype == "omni": # omni write_omni_affine(filename, affine_mat) elif atype == "afni": # afni write_afni_affine(filename, affine_mat) elif atype == "fsl": # fsl write_fsl_affine(filename, affine_mat) else: # Unknown extension raise ValueError("Unknown affine type: {}".format(atype))
[docs]def convert_affine_file( output: str, filename: str, output_atype: str, invert: bool = False, target: str = None, source: str = None ) -> None: """Converts input affine file to output affine file of another type. Parameters ---------- output: str Path/name of output affine file. filename: str Affine file to convert. output_atype: str Type of affine to output (omni/afni/fsl). invert: bool Controls whether the affine should be inverted. target: str Path to target image affine is transformed to (required for fsl conversion). source: str Path to source image affine is applying transform to (required for fsl conversion). """ # open the affine file to convert affine_mat, atype = read_affine_file(filename) # load target and source images if defined if target and source: t = nib.load(target) s = nib.load(source) else: t = None s = None # convert the affine to output type new_affine_mat = convert_affine(affine_mat, atype, output_atype, invert=invert, target=t, source=s) # write the new affine to file write_affine_file(output, new_affine_mat, output_atype)
[docs]def write_regress_params(filename: str, regress_params: np.ndarray) -> None: """Writes regression parameters to disk.""" # add extension if not exist _, ext = os.path.splitext(filename) if ext != ".regress": filename += ".regress" # write data to file with open(filename, "w") as f: np.savetxt(f, regress_params)
[docs]def write_rb_params(filename: str, rb_params: np.ndarray) -> None: """Writes rigid body params to disk. Parameters ---------- filename: str Rigid body params file to write. rb_params: str n x 6 ndarray containing rigid body parameters. """ # add extension if not exist _, ext = os.path.splitext(filename) if ext != ".params": filename += ".params" with open(filename, "w") as f: np.savetxt(f, rb_params, fmt="%.6f", header="x(mm) y(mm) z(mm) rx(rad) ry(rad) rz(rad)")