-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MR image data representation as NiftiImages #1044
Comments
We discussed the issue of the data dimensions many times (see e.g. #315) but could never agree on it. |
The patient is a 3D object, but they can change in time (for example beating heart), or you can inject a contrast agent that changes the image intensities, or you might look at more than one tissue property such as T1, T2, water, fat etc. or you might acquire data multiple times for future averaging. We should use the power of the computer language to handle the mapping from dimensions to storage in memory. If we try to put everything into a 3D array, we will end up having to do ourselves a lot of conversions of indices from our physical dimensions to this 3D array. I see broadly two options: |
As discovered in #1186 we currently have a crash when constructing At present, conversion to SIRF/src/Registration/cReg/NiftiImageData.cpp Line 101 in d034e4c
and then copies data across. However, the creation is based only on the geom_info which contains no information on repetitions, contrast etc, therefore creating an image with only 1 repetition/contrast etc. The copy will then segfault as it writes in non-allocated memory. #1226 is working around this by only copying data from the first volume, but this is of course not-ideal.
As Some pointers:
From this, it seems that it might not be too hard to "collapse" all MR dimensions into the Nifti dynamic field, or use NiftiImageData<dataType>& NiftiImageData<dataType>::operator=(const ImageData& to_copy)
{
...
auto nii_ptr = dynamic_cast<const NiftiImageData<dataType> * const >(&to_copy);
if (nii_ptr) {
// Check the image is copyable
if (!nii_ptr->is_initialised())
throw std::runtime_error("Trying to copy an uninitialised image.");
copy_nifti_image(_nifti_image,nii_ptr->_nifti_image);
this->_data = static_cast<float*>(_nifti_image->data);
this->_original_datatype = nii_ptr->_original_datatype;
set_up_geom_info();
}
else {
int num_time_frames = 1;
int num_repetitions = 1;
...
if (auto mr_ptr = dynamic_cast<const MRImageData<dataType> * const >(&to_copy))
{
num_time_frames = ...; etc
}
// temp class to store repetition
VolumeInfo vol_info(num_time_frames, num_repetitions, ...);
this->_nifti_image = NiftiImageData<float>::create_from_geom_info(*to_copy.get_geom_info_sptr(), vol_info);
}
} |
@ashgillman maybe you have some more experience with this. |
Just came across this. I did read this page recently that I don't think you linked, the documentation on My 2c, I think Kris' suggestion is quite sane: to "ravel"/"unravel" (in numpy language) these different dimensions into one. But not dim 4.
|
But when you unravel, you need to know the size of each dimension and that is not in the intent code? I'm not sure what is the point of forcing multi-dimensional data into a single dimension of NIfTI when no-one else will be able to decode the new NIfTI? What I do in other code is tell my reading programme what parameters I want in dimensions 3+ of my output array. For example, specifying {'slice', 'dynamic'} gives an array that is [nrows ncolumns nslices ndynamics] , or, {'slice','echo'} gives an array that is [nrows ncolumns nslices nechos]. |
Yes, that's why it would be encoded it in the intent_name.
I thought the issue was we have only 3 dims to play with in NIfti (5, 6, 7) and 4 dimensions to stuff (channel, phase, reps, sets)?
Assuming that you'll never need more than 3 dims (does seem quite unlikely to me?) then yes I think this makes more sense to me, to put a key like that into intent_name and have it code what is in dims 5, 6, 7. |
Thanks @ashgillman. Great link to the Nifti doc. Just to repeat
All solutions will be unsatisfactory. This is true for PET as well. Nifti doesn't store all we need to know (it doesn't even store time frame info). Something to remember is that a SIRF Given our rate of deciding/implementing this kind of thing, a simple solution is needed though. I personally have no idea how we currently handle this in @ckolbitsch, tagging you as well... |
Sorry - I mis-understood.
I don't limit the number of dimensions. This was just an example. |
There is a fundamental issue in our approach of trying to convert MR data into the Nifti images objects.
MR data have many different dimensions, obviously 3 spatial ones, but the additional ones (at least defined in ISMRMRD) are:
Currently, we try to take a set of MR reconstructions and convert it into a 3D image. This can't work.
When we are trying to convert these into a 3D Nifti image this requires that
a) the images are consistent wrt their content, (e.g. no images of two slices from contrasts should appear in the same image)
2) the multi-slice 2D acquisitions are placed correctly (i.e. slice thickness and slice distance are taken into account separately and correctly)
The good news is: our reconstructions stored in our image containers are
ISMRMRD::Image
objects so all our reconstructions already contain the correct information in their header. Our attempt of converting it into a single 3D space is, however, flawed.The text was updated successfully, but these errors were encountered: