OpenwaterHealth / OpenLIFU-python

focused ultrasound toolbox
GNU Affero General Public License v3.0
8 stars 2 forks source link

Load Volume from Nifti #84

Open peterhollender opened 1 month ago

peterhollender commented 1 month ago

We decided to store volumetric data in the NIfTI1 format, because the volumes can store spatial orientation data (as a transform), and be loaded natively into slicer. I'm not quite sure how to implement this into the Database class, though. In MATLAB, I created a Volume class that was essentially an xarray.DataArray - it has voxel data with units, named coordinate axes with values and units, a transform matrix, and a flexible attribute dictionary. I think we can probably use xarray.DataArray here as well, although nibabel.Nifti1Image, which is what nibabel.nifti1.load returns, may be suitable on it's down (although I'm not as comfortable operating on the underlying data). I know vtk has a number of volumetric data formats which I'm guessing will be used in visualization, as well, although again - ease of use for processing is also a factor. I'm probably going to try to load from .nii to an xarray.DataArray, but I welcome other suggestions

ebrahimebrahim commented 1 month ago

I'm actually not too familiar with the Xarray library, but from a cursory look it looks like xarray.DataArray is a thin wrapper around a numpy array, which is a very friendly and standard format to work with for python users. I like the xarray.DataArray option. I agree that it doesn't make sense to have the underlying data structure that openlifu operates on be a vtk structure, that is more for visualization. And since OpenLIFU + visualization is mainly going to be achieved via the SlicerOpenLIFU extension, the visualizable representation of volumes is going to be a Slicer volume mrml node, which internally handles the vtk stuff. OpenLIFU-python can focus more on making data structures user friendly for algorithm development rather than for visualization.

Loading to xarray.DataArray rather than than keeping the nibabel.Nifti1Image also can make it easier to extend the IO aspects of openlifu later so that possibly multiple volume file formats can be handled. When developing the file loading code, it would be good to keep that I/O code cordoned off in a separate module as much as possible.

peterhollender commented 1 month ago

I added the method, but I'm not sure I like the way I did it. There is currently a static method in openlifu.db.Database called _load_nifti that reads a nii, accepts an optional metadata dict, and creates the xarray.DataArray. When called from openlifu.db.Database.load_volume, it handles retrieving that metadata from the associated .json file and creating the volume correctly, but it seems like openlifu.db.Database._load_nifti is not the correct home for that method - it should just be load_nifti and located somewhere else in the hierarchy.

ebrahimebrahim commented 1 month ago

Yes maybe it belongs in openlifu.io?