"""Load mixed media files for Skyline from disk paths.
``EMERGENCY_REF`` supplies a fallback NIfTI header (MNI-like spacing) when
tractograms must load before any matching reference image is available.
"""
import numpy as np
from dipy.io.image import load_nifti
from dipy.io.peaks import load_pam
from dipy.io.streamline import load_tractogram
from dipy.io.surface import load_gifti, load_pial
from dipy.io.utils import create_nifti_header, split_filename_extension
from dipy.utils.logging import logger
mni_2009c = {
"affine": np.array(
[
[1.0, 0.0, 0.0, -96.0],
[0.0, 1.0, 0.0, -132.0],
[0.0, 0.0, 1.0, -78.0],
[0.0, 0.0, 0.0, 1.0],
]
),
"dims": (193, 229, 193),
"vox_size": (1.0, 1.0, 1.0),
"vox_space": "RAS",
}
EMERGENCY_REF = create_nifti_header(
mni_2009c["affine"], mni_2009c["dims"], mni_2009c["vox_size"]
)
def _reference_from_image(data, affine):
"""Build a NIfTI header usable as a tractogram spatial reference.
Formats without an embedded header (``.tck``, ``.vtk``, ``.dpy``, ...) need
a full reference, not just an affine.
Parameters
----------
data : ndarray
Volume the reference geometry is taken from.
affine : ndarray, shape (4, 4)
Voxel-to-world transform of ``data``.
Returns
-------
nibabel.nifti1.Nifti1Header
Header carrying the volume's affine, dimensions and voxel sizes.
"""
vox_size = np.linalg.norm(affine[:3, :3], axis=0)
return create_nifti_header(affine, data.shape[:3], vox_size)
[docs]
def load_files(fnames, *, rois=None, shm_coeffs=None):
"""Load the provided list of files.
Parameters
----------
fnames : list of str
Path of the file.
rois : list of str, optional
Paths of the ROIs.
shm_coeffs : list of str, optional
Paths of the SH coefficients files.
Returns
-------
dict
Dictionary containing the loaded images, peaks, ROIs, surfaces,
tractograms, and spherical-harmonic coefficient data.
"""
if fnames is None:
fnames = []
if rois is None:
rois = []
if shm_coeffs is None:
shm_coeffs = []
skyline_images = []
skyline_peaks = []
skyline_rois = []
skyline_surfaces = []
skyline_tractograms = []
skyline_shm_coeffs = []
for fname in fnames:
logger.info(f"Loading file ... \n{fname}\n")
_, ext = split_filename_extension(fname)
ext = ext.lower()
if ext in [".nii.gz", ".nii"]:
data, affine = load_nifti(fname)
skyline_images.append((data, affine, fname))
elif ext == ".pam5":
pam = load_pam(fname)
skyline_peaks.append((pam, fname))
elif ext == ".pial":
surface = load_pial(fname)
if surface:
vertices, faces = surface
skyline_surfaces.append((vertices, faces, fname))
elif any(ext.endswith(_ext) for _ext in [".gii", ".gii.gz"]):
surface = load_gifti(fname)
vertices, faces = surface
if len(vertices) and len(faces):
vertices, faces = surface
skyline_surfaces.append((vertices, faces, fname))
else:
logger.warning(
f"{fname} does not have any surface geometry.", stacklevel=2
)
elif ext in [".trk", ".trx"]:
sft = load_tractogram(fname, "same", bbox_valid_check=False)
skyline_tractograms.append((sft, fname))
elif ext in [".dpy", ".tck", ".vtk", ".vtp", ".fib"]:
if skyline_images:
sft = load_tractogram(
fname,
_reference_from_image(*skyline_images[0][:2]),
bbox_valid_check=False,
)
else:
sft = load_tractogram(fname, EMERGENCY_REF)
skyline_tractograms.append((sft, fname))
elif ext == ".npy":
# To support horizon BUAN p-values file
pass
else:
logger.error(f"File extension '{ext}' is not supported in Skyline.")
for fname in rois:
logger.info(f"Loading file ... \n{fname}\n")
_, ext = split_filename_extension(fname)
ext = ext.lower()
if ext in [".nii.gz", ".nii"]:
data, affine = load_nifti(fname)
skyline_rois.append((data, affine, fname))
else:
logger.error(
f"File extension '{ext}' is not supported for ROIs in Skyline."
)
for fname in shm_coeffs:
logger.info(f"Loading file ... \n{fname}\n")
_, ext = split_filename_extension(fname)
ext = ext.lower()
if ext == ".pam5":
pam = load_pam(fname)
skyline_shm_coeffs.append((pam.shm_coeff, pam.affine, fname, "descoteaux"))
return {
"images": skyline_images,
"peaks": skyline_peaks,
"rois": skyline_rois,
"surfaces": skyline_surfaces,
"tractograms": skyline_tractograms,
"shm_coeffs": skyline_shm_coeffs,
}
[docs]
def load_npy(fname):
"""Load a numpy file containing BUAN color values.
Parameters
----------
fname : str
Path to the .npy file.
Returns
-------
np.ndarray
The loaded numpy array.
"""
try:
data = np.load(fname)
return data
except Exception as e:
logger.error(f"Error loading numpy file '{fname}': {e}")
return None