Source code for omni.interface

"""Python/C++ Interface for Omni.

    This file contains the python side wrapper for the
    underlying C++ code.
"""
import os
import sys
import warnings
from typing import List
import numpy as np
import nibabel as nib

# first try loading the development library if available
try:
    # get the top level directory
    PARENT_DIR = os.path.dirname(os.path.dirname(__file__))
    # if the build folder exists, add to path
    if "build" in os.listdir(PARENT_DIR):
        sys.path.insert(0, os.path.join(PARENT_DIR, "build"))
    else:
        raise ImportError
    # import the omni C++ module from build
    from omni_lib import omni

    print("omni C++ module loaded from development build!")
except ImportError as e:
    # try to load the omni C++ modules
    try:
        from omni_cpp import omni
    except ImportError:
        warnings.warn("omni C++ modules not found. This may be intentional or the omni install has failed.")


[docs]class OmniInterface: """Wrapper for interface object. Does python level preprocessing before hand over to the C++ backend. Methods ------- set_img: Sets an image to pass into the C++ interface. get_img: Gets an image from the C++ interface. """ def __init__(self, *args, **kwargs): """Initialize interface.""" # initialize and store reference to interface object self._interface = omni.Interface(*args, **kwargs) @property def link(self): """Returns the _interface object for direct access.""" return self._interface @link.setter def link(self, x): pass
[docs] def set_img(self, name: str, image: nib.Nifti1Image) -> None: """Stores a Nifti1Image in omnireg database at "name". Parameters ---------- name: str Key to save the image at in C++ interface table. image: nib.Nifti1Image Image to save. """ # check if image is a Nifti1Image assert isinstance(image, nib.Nifti1Image), "image is not a Nifti1Image" # get data (squeeze out any singleton dims) data = np.squeeze(image.get_fdata()) # check dim size, throw error if >3 assert len(data.shape) == 3, "omni does not yet support non-3D images!" # store in database self._interface.set_img(name, np.squeeze(image.get_fdata()), image.affine)
[docs] def get_img( self, name: str, affine: np.ndarray = None, ref: nib.Nifti1Image = None, clip: List[float] = None ) -> nib.Nifti1Image: """Returns a Nifti1Image from the array stored at "name". Uses default nibabel image header information if affine/header is not defined. The ref variable can also be used to specify the image header information. Parameters ---------- name: str Key for image to get from C++ interface table. affine: np.ndarray Affine to use for returned image. ref: nib.Nifti1Image Reference image to use for header of returned image. clip: List[float] Clipping limits to apply to image data. Returns ------- nib.Nifti1Image Return image represented by key from C++ interface. """ # get the array data array = self._interface.return_array(name) # clip array if clip: array = np.clip(array, clip[0], clip[1]) # check method inputs if affine is not None and ref is not None: raise ValueError("Ambiguous Input: affine/ref should " "not all be defined at the same time.") elif ref is not None: # check inputs assert isinstance(ref, nib.Nifti1Image), "ref type is not Nifti1Image" # return image return nib.Nifti1Image(array, ref.affine, ref.header) elif affine is not None: # check inputs assert isinstance(affine, np.ndarray), "affine not a numpy array" assert affine.shape == (4, 4), "affine shape not (4,4)" # return image return nib.Nifti1Image(array, affine) else: # return defaults with image return nib.Nifti1Image(array, np.eye(4))