@@ -440,12 +440,14 @@ MINCImageIO::ReadImageInformation()
440440 itkExceptionStringMacro (" minc files without spatial dimensions are not supported!" );
441441 }
442442
443- if (m_MINCPImpl->m_DimensionIndices [0 ] != -1 && m_MINCPImpl->m_DimensionIndices [4 ] != -1 )
444- {
445- itkExceptionStringMacro (" 4D minc files vector dimension are not supported currently" );
446- }
443+ const bool haveTimeDimension = (m_MINCPImpl->m_DimensionIndices [4 ] != -1 );
447444
448- this ->SetNumberOfDimensions (spatial_dimension_count);
445+ // The MINC time dimension becomes an additional (highest) ITK dimension, while
446+ // the MINC vector_dimension is mapped to ITK components. The two are
447+ // independent and may coexist (e.g. a 4D vector image).
448+ const unsigned int itkDimensionCount = spatial_dimension_count + (haveTimeDimension ? 1 : 0 );
449+
450+ this ->SetNumberOfDimensions (itkDimensionCount);
449451
450452 int numberOfComponents = 1 ;
451453 unsigned int usableDimensions = 0 ;
@@ -457,11 +459,37 @@ MINCImageIO::ReadImageInformation()
457459 auto RAStofromLPS = Matrix<double , 3 , 3 >::GetIdentity ();
458460 RAStofromLPS (0 , 0 ) = -1.0 ;
459461 RAStofromLPS (1 , 1 ) = -1.0 ;
460- std::vector<double > dir_cos_temp (3 );
462+ std::vector<double > dir_cos_temp (itkDimensionCount, 0.0 );
461463
462464 Vector<double , 3 > origin{};
463465 Vector<double , 3 > oOrigin{};
464466
467+ // Build the MINC apparent dimension order slowest-varying first. The time
468+ // dimension is the slowest, matching the ITK buffer layout used by
469+ // Read()/Write() where it is the highest ITK dimension.
470+ if (haveTimeDimension)
471+ {
472+ m_MINCPImpl->m_MincApparentDims [usableDimensions] = m_MINCPImpl->m_MincFileDims [m_MINCPImpl->m_DimensionIndices [4 ]];
473+ // always use positive
474+ miset_dimension_apparent_voxel_order (m_MINCPImpl->m_MincApparentDims [usableDimensions], MI_POSITIVE );
475+ misize_t _sz = 0 ;
476+ miget_dimension_size (m_MINCPImpl->m_MincApparentDims [usableDimensions], &_sz);
477+ double _sep = NAN ;
478+ miget_dimension_separation (m_MINCPImpl->m_MincApparentDims [usableDimensions], MI_ORDER_APPARENT , &_sep);
479+ double _start = NAN ;
480+ miget_dimension_start (m_MINCPImpl->m_MincApparentDims [usableDimensions], MI_ORDER_APPARENT , &_start);
481+
482+ this ->SetDimensions (spatial_dimension_count, static_cast <unsigned int >(_sz));
483+ this ->SetSpacing (spatial_dimension_count, _sep);
484+ this ->SetOrigin (spatial_dimension_count, _start);
485+
486+ std::vector<double > time_dir (itkDimensionCount, 0.0 );
487+ time_dir[spatial_dimension_count] = 1.0 ;
488+ this ->SetDirection (spatial_dimension_count, time_dir);
489+
490+ ++usableDimensions;
491+ }
492+
465493 // minc api uses inverse order of dimensions , fastest varying are last
466494 Vector<double , 3 > sep;
467495 for (int i = 3 ; i > 0 ; i--)
@@ -530,18 +558,6 @@ MINCImageIO::ReadImageInformation()
530558 ++usableDimensions;
531559 }
532560
533- if (m_MINCPImpl->m_DimensionIndices [4 ] != -1 ) // have time dimension
534- {
535- // micopy_dimension(hdim[m_MINCPImpl->m_DimensionIndices[4]],&apparent_dimension_order[usable_dimensions]);
536- m_MINCPImpl->m_MincApparentDims [usableDimensions] = m_MINCPImpl->m_MincFileDims [m_MINCPImpl->m_DimensionIndices [4 ]];
537- // always use positive
538- miset_dimension_apparent_voxel_order (m_MINCPImpl->m_MincApparentDims [usableDimensions], MI_POSITIVE );
539- misize_t _sz = 0 ;
540- miget_dimension_size (m_MINCPImpl->m_MincApparentDims [usableDimensions], &_sz);
541- numberOfComponents = _sz;
542- ++usableDimensions;
543- }
544-
545561 // Set apparent dimension order to the MINC2 api
546562 if (miset_apparent_dimension_order (m_MINCPImpl->m_Volume , usableDimensions, m_MINCPImpl->m_MincApparentDims ) < 0 )
547563 {
@@ -893,33 +909,9 @@ MINCImageIO::WriteImageInformation()
893909 MetaDataDictionary & thisDic = GetMetaDataDictionary ();
894910
895911 unsigned int minc_dimensions = 0 ;
896- if (nComp > 3 ) // last dimension will be either vector or time
897- {
898- micreate_dimension (MItime,
899- MI_DIMCLASS_TIME ,
900- MI_DIMATTR_REGULARLY_SAMPLED ,
901- nComp,
902- &m_MINCPImpl->m_MincApparentDims [m_MINCPImpl->m_NDims - minc_dimensions - 1 ]);
903-
904- double tstart = 0.0 ;
905- if (!ExposeMetaData<double >(thisDic, " tstart" , tstart))
906- {
907- tstart = 0.0 ;
908- }
909-
910- miset_dimension_start (m_MINCPImpl->m_MincApparentDims [m_MINCPImpl->m_NDims - minc_dimensions - 1 ], tstart);
911-
912- double tstep = 1.0 ;
913- if (!ExposeMetaData<double >(thisDic, " tstep" , tstep))
914- {
915- tstep = 1.0 ;
916- }
917-
918- miset_dimension_separation (m_MINCPImpl->m_MincApparentDims [m_MINCPImpl->m_NDims - minc_dimensions - 1 ], tstep);
919-
920- ++minc_dimensions;
921- }
922- else if (nComp > 1 )
912+ // ITK components are always written as a MINC vector_dimension (fastest
913+ // varying). A time series is an ITK dimension, not components (see below).
914+ if (nComp > 1 )
923915 {
924916 micreate_dimension (MIvector_dimension,
925917 MI_DIMCLASS_RECORD ,
@@ -956,10 +948,20 @@ MINCImageIO::WriteImageInformation()
956948 ++minc_dimensions;
957949 }
958950
959- if (nDims > 3 )
951+ if (nDims > 4 )
960952 {
961953 MINCIOFreeTmpDimHandle (minc_dimensions, m_MINCPImpl->m_MincApparentDims );
962- itkExceptionStringMacro (" Unfortunately, only up to 3D volume are supported now." );
954+ itkExceptionStringMacro (" Unfortunately, only up to 4D volumes (3 spatial + time) are supported." );
955+ }
956+
957+ if (nDims > 3 ) // the 4th ITK dimension is written as a MINC time dimension (slowest varying)
958+ {
959+ micreate_dimension (MItime,
960+ MI_DIMCLASS_TIME ,
961+ MI_DIMATTR_REGULARLY_SAMPLED ,
962+ this ->GetDimensions (3 ),
963+ &m_MINCPImpl->m_MincApparentDims [m_MINCPImpl->m_NDims - minc_dimensions - 1 ]);
964+ ++minc_dimensions;
963965 }
964966
965967 // allocating dimensions
@@ -994,21 +996,18 @@ MINCImageIO::WriteImageInformation()
994996 for (unsigned int i = 0 ; i < nDims; ++i)
995997 {
996998 const unsigned int j = i + (nComp > 1 ? 1 : 0 );
997- double dir_cos[3 ];
998- for (unsigned int k = 0 ; k < 3 ; ++k)
999+ const unsigned int apparentIndex = minc_dimensions - j - 1 ;
1000+ miset_dimension_separation (m_MINCPImpl->m_MincApparentDims [apparentIndex], this ->GetSpacing (i));
1001+ miset_dimension_start (m_MINCPImpl->m_MincApparentDims [apparentIndex], origin[i]);
1002+ if (i < 3 ) // spatial dimension: also set the direction cosines (time has none)
9991003 {
1000- if (k < nDims)
1004+ double dir_cos[3 ];
1005+ for (unsigned int k = 0 ; k < 3 ; ++k)
10011006 {
1002- dir_cos[k] = directionCosineMatrix[i][k];
1003- }
1004- else
1005- {
1006- dir_cos[k] = 0.0 ;
1007+ dir_cos[k] = (k < nDims) ? directionCosineMatrix[i][k] : 0.0 ;
10071008 }
1009+ miset_dimension_cosines (m_MINCPImpl->m_MincApparentDims [apparentIndex], dir_cos);
10081010 }
1009- miset_dimension_separation (m_MINCPImpl->m_MincApparentDims [minc_dimensions - j - 1 ], this ->GetSpacing (i));
1010- miset_dimension_start (m_MINCPImpl->m_MincApparentDims [minc_dimensions - j - 1 ], origin[i]);
1011- miset_dimension_cosines (m_MINCPImpl->m_MincApparentDims [minc_dimensions - j - 1 ], dir_cos);
10121011 }
10131012
10141013 // TODO: fix this to appropriate
@@ -1107,14 +1106,14 @@ MINCImageIO::WriteImageInformation()
11071106 break ;
11081107 case ' t' :
11091108 case ' T' :
1110- if (nComp <= 1 )
1109+ if (nDims <= 3 ) // no time dimension present
11111110 {
11121111 itkDebugMacro (" Dimension order is incorrect " << dimension_order);
11131112 dimorder_good = false ;
11141113 }
11151114 else
11161115 {
1117- j = m_MINCPImpl-> m_NDims - 1 ;
1116+ j = 0 ; // time is the slowest-varying apparent dimension
11181117 }
11191118 break ;
11201119 case ' x' :
0 commit comments