I was wondering if anyone could help point me in the right direction.
I have a bunch of itk::Image<type, 3> 3D images that I would like to combine into a
single 4D file written out using itk::NiftiImageIO. I have looked around and
tried several approaches such as using JoinSeriesImageFilter but I seem not
to be getting the results I’m looking for, perhaps the output I have gotten thus far is wrong.
the general Idea I have tried thus far is as follow
// bear in mind --> template <class RType>
typedef itk::Image<RType, 3> InputImageType;
typedef itk::Image<RType, 4> OutputImageType;
typedef itk::ImageFileWriter<OutputImageType> WriterType;
// pseudo code, assume there are at least 1 or more valid images in the vector.
std::vector<typename InputImageType::Pointer> itkImages;
size_t sizeOfImages = itkImages.size();
// Combine all 3D images to one single 4D.
//----------------------------------------------------
typedef itk::JoinSeriesImageFilter<InputImageType, OutputImageType> JoinSeriesImageType;
auto jointSeriesImage = JoinSeriesImageType::New();
jointSeriesImage->SetOrigin(0.0); // this isn't necessary as it's the default anyway
jointSeriesImage->SetSpacing(1.0); // this isn't necessary as it's the default anyway
for (unsigned int idx = 0; idx < sizeOfImages; idx++)
{
typename InputImageType::Pointer image = itkImages[idx];
jointSeriesImage->SetInput(idx, image);
}
jointSeriesImage->Update();
typename OutputImageType::Pointer outputImage = jointSeriesImage->GetOutput();
// Write the image to a file using ITK's NIfTI writer.
//----------------------------------------------------
typename WriterType::Pointer writer = WriterType::New();
writer->SetFileName(pathBuffer);
writer->SetInput(outputImage);
itk::NiftiImageIO::Pointer imageIO = itk::NiftiImageIO::New();
imageIO->SetLegacyAnalyze75Mode(itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeReject);
writer->SetImageIO(imageIO);
writer->Update();
Is there anything wrong / off in the above code, if so could anyone give me some pointers. Thanks.
I have slices represented as 3D images (NifTi) as per the above code
typedef itk::Image<RType, 3> InputImageType
that I wish to combine into one whole 4D image and saved as one file
typedef itk::Image<RType, 4> OutputImageType
as opposed to saving them individually.
The issue is that when I run the code I had posted earlier, a single file is indeed generated, however when I try to view the file, it looks nothing like what I would expect from the individual 3D images.
here is the image of the top most slice (3D image)
I guess, I just want to know if the approach in the code presented earlier is the way to do, if so this might mean the issue is somewhere in my codebase.
Could you kindly elaborate what you mean by RGB pixel type? I have the function templates whereby RType could be int8_t, int16_t, float, double etc. Thanks.
Do you want to write segmentation that contains overlapping segments into a NIFTI file? As far as I know, no such convention exists for this format. Due to rigidity of NIFTI file header, it would not be possible to create a standard NIFTI file that contains metadata describing how to properly interpret you 4D volume.
In contrast, NRRD files (with 3D Slicer’s segmentation metadata convention) has been used widely for this purpose for a long time. This format can use a single shared 3D volume between non-overlapping segments, so most segmentations fit in a few 3D volumes in the 4D file. For example, if you have 300 non-overlapping brain structures segmented and you define an additional region that overlaps with some of those structures, then you don’t need to store 301 but only 2 volumes in the 4D file. This file format can also store standard coded terms to specify the meaning of each segment. You can find the file specification here. You can read/write segments in Python using slicerio package. There is also a topic about how to create such files using ITK.
Hi Philip,
Not at all, I’m not writing as an RGBA, it’s simply single values for each voxels (grayscale).
I’m starting to think the issue may well be due to the rigidity / limitation of NifTi as hinted by @lassoan .
Thanks for the detailed response. I’m leaning towards the issue being the way NifTi headers are, I’m not that conversant with the whole idea of overlapping segments in all honesty, however I perhaps had the naive idea that I could do just for lack of a better word concatenate the 3D images all into one single 4D based on the example in itkJoinSeriesImageFilterTest.
I guess I would need to research a bit more into this whole issue as well as look into 3D Slicer’s segmentation metadata convention for whatever it’s worth and then take it from there.
Thanks
You should be able to “concatenate” the images like that, assuming they all have the same size. What happens if you try concatenating MRIs instead of label maps?
If segments don’t overlap (each image voxel can only belong to one segment) then you don’t need a 4D volume, but you can store the labels in a single 3D volume. It is very simple and efficient, this is how most software store image segmentations.