Temporal Dimension Semantics in 2D + Time Image Series Written Out As 3D Image

Hello Everyone,

Given a bunch of 2D frames in a temporal series, what is the intended way in ITK to write those out to be recognised as 2D + t image, not just as 3D image?

I’m asking because ITK-Snap or Slicer display 3D DICOM images (written out this way, naturally, :man_shrugging:) as single time-step image. This is from converting VFSS .avi to DICOM for analysis, which is not ideal.

What is the most straightforward intended way and, specifically, format to preserve temporal series semantics (preferably without having to fiddle with DICOM tags)?

If you use NRRD file format then you can specify the kind of each axis. For example:

  • kinds: domain domain domain: 3D image
  • kinds: time domain domain: 2D+t image

In 3D Slicer, we recognize many 2D time sequence image acquisitions, such as fluoroscopy, ultrasound, cine-MRI. Therefore, VFSS is loaded as a time sequence (when it is loaded properly with the DICOM module). If you experience a different behavior in the latest Slicer version then let me know.

2 Likes

Thank you, Andras (@lassoan).

I’ve had a quick look at itk::NrrdImageIO, but I’m unclear how/where to specify the kind of each axis, when writing NRRD (.nhdr). Or, does it have to be passed to NrrdImageIO via itk::MetaDataDictionary? I can’t find a working example to set those axis kinds. :grimacing:

Would you be able to point me to an example, perhaps, in Python?

PS. With our stand-alone GE Fluorostar we can’t get DICOM export to work correctly, and GE support are dragging their feet with addressing the issue with this unit. So, at this stage I’m forced to export AVIs, and then convert those to something suitable for analysis. Not ideal, but kinda have to play along at this stage, :grimacing:

Oh, doing further searching and found this post:

I’m doing attempting this sort of thing now, setting kinds tags:

img.GetMetaDataDictionary()['kinds'] = 'time domain domain'

But this doesn’t end up in the output .nrrd header metadata. I still end up with:

kinds: domain domain domain

I’ve tried setting the kinds tag in MetaDataDictionary dictionaries in all these:

  1. the image,
  2. the writer filter,
  3. the image IO (NrrdImageIO).

And yet, somehow, in the output I don’t see the time domain.

Would you suggest what I’m doing wrong here?

You might need this pattern:

meta_data = img.GetMetaDataDictionary()
meta_data['kinds'] = 'time domain domain'
img.SetMetaDataDictionary(meta_data)

Thank you, Dženan (@dzenanz), for the tip.

I’ve followed, and now the header comes out like this, where kinds appears as a field, and as a key/value pair, which doesn’t look right — something is rotten in the state of Denmark:

NRRD0004
# Complete NRRD file format specification at:
# http://teem.sourceforge.net/nrrd/format.html
type: unsigned char
dimension: 3
space: left-posterior-superior
sizes: 1024 1280 13
space directions: (1,0,0) (0,1,0) (0,0,1)
kinds: domain domain domain
encoding: raw
space origin: (0,0,0)
kinds:=time domain domain

I did a bit of reading/searching and there’s this (How to write a custom Tag to an image (NRRD or other) header - #6 by jonasteuwen):

But then, the NRRD format spec (Teem: nrrd: Definition of NRRD File Format) says kinds is a field, not just a key/value pair.

Any further tips how to get this right?

It would seem something of this sort (basic image IO) should be closer to the surface, no?

@lassoan — Andras, following your invitation to test in latest 3D Slicer and post here.

I’ve downloaded 3D Slicer 5.6.2. When loading NRRD with this header (manually edited for the sake of the exercise, but following the specs)

NRRD0004
# Complete NRRD file format specification at:
# http://teem.sourceforge.net/nrrd/format.html
type: unsigned char
dimension: 3
space: left-posterior-superior
sizes: 1024 1280 13
space directions: (1,0,0) (0,1,0) none
kinds: domain domain time
encoding: raw
space origin: (0,0,0)

it appears the image is still loaded as a 3D volume, judging from the spacing, etc., not time series:

It is likely I’m misunderstanding something — would you please comment?

In 3D Slicer everything is in 3D. If you have a 2D image slice then we want to be able to put it anywhere at any orientation. Therefore, regardless if the image has one or more slices, it must to have 3 dimensional domain and so the header should contain kinds: domain domain domain time and all spatial positions and directions should have 3 components.

You can go to Sample Data module, download the cardiac CT time sequence image, save it, and have a look at the header. Or you can create a 4D sequence using this Python script.

Thank you, Andras (@lassoan) — I’ll have a play with this.