Skip to content

Commit 9fd78f6

Browse files
committed
re #1124: Fixed issue of vtkVirtualDiscCapture creating images with inconsistent dimensionality information in the header (fix backported to stable branch)
1 parent 888deab commit 9fd78f6

File tree

8 files changed

+75
-67
lines changed

8 files changed

+75
-67
lines changed

PlusLib/src/PlusCommon/IO/vtkPlusMetaImageSequenceIO.cxx

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ bool vtkPlusMetaImageSequenceIO::CanWriteFile( const std::string& filename )
582582
//----------------------------------------------------------------------------
583583
/** Writes the spacing and dimensions of the image.
584584
* Assumes SetFileName has been called with a valid file name. */
585-
PlusStatus vtkPlusMetaImageSequenceIO::OpenImageHeader()
585+
PlusStatus vtkPlusMetaImageSequenceIO::WriteInitialImageHeader()
586586
{
587587
if( this->TrackedFrameList->GetNumberOfTrackedFrames() == 0 )
588588
{
@@ -592,7 +592,7 @@ PlusStatus vtkPlusMetaImageSequenceIO::OpenImageHeader()
592592

593593
// First, is this 2D or 3D?
594594
bool isData3D = ( this->TrackedFrameList->GetTrackedFrame( 0 )->GetFrameSize()[2] > 1 );
595-
bool isDataTimeSeries = this->TrackedFrameList->GetNumberOfTrackedFrames() > 1;
595+
bool isDataTimeSeries = this->IsDataTimeSeries; // don't compute it from the number of frames because we may still have only one frame but acquire more frames later
596596

597597
// Override fields
598598
this->NumberOfDimensions = isData3D ? 3 : 2;
@@ -604,12 +604,7 @@ PlusStatus vtkPlusMetaImageSequenceIO::OpenImageHeader()
604604
{
605605
this->NumberOfDimensions++;
606606
}
607-
608-
{
609-
std::stringstream ss;
610-
ss << this->NumberOfDimensions;
611-
SetCustomString( "NDims", ss.str() );
612-
}
607+
SetCustomString("NDims", this->NumberOfDimensions);
613608

614609
SetCustomString( "BinaryData", "True" );
615610
SetCustomString( "BinaryDataByteOrderMSB", "False" );
@@ -629,7 +624,7 @@ PlusStatus vtkPlusMetaImageSequenceIO::OpenImageHeader()
629624
else
630625
{
631626
SetCustomString( "CompressedData", "False" );
632-
SetCustomString( SEQMETA_FIELD_COMPRESSED_DATA_SIZE, NULL );
627+
SetCustomString( SEQMETA_FIELD_COMPRESSED_DATA_SIZE, (const char*)(NULL) );
633628
}
634629

635630
unsigned int frameSize[3] = {0, 0, 0};
@@ -669,7 +664,7 @@ PlusStatus vtkPlusMetaImageSequenceIO::OpenImageHeader()
669664
}
670665

671666
// Update NDims and Dims fields in header
672-
this->GenerateFrameSizeCustomStrings( this->TrackedFrameList->GetNumberOfTrackedFrames(), isData3D );
667+
this->UpdateDimensionsCustomStrings( this->TrackedFrameList->GetNumberOfTrackedFrames(), isData3D );
673668

674669
// PixelType
675670
if ( this->TrackedFrameList->IsContainingValidImageData() )
@@ -692,9 +687,7 @@ PlusStatus vtkPlusMetaImageSequenceIO::OpenImageHeader()
692687
{
693688
this->NumberOfScalarComponents = this->TrackedFrameList->GetNumberOfScalarComponents();
694689
}
695-
std::ostringstream ss;
696-
ss << this->NumberOfScalarComponents;
697-
SetCustomString( "ElementNumberOfChannels", ss.str().c_str() );
690+
SetCustomString("ElementNumberOfChannels", this->NumberOfScalarComponents);
698691
}
699692

700693
SetCustomString( SEQMETA_FIELD_US_IMG_ORIENT, PlusVideoFrame::GetStringFromUsImageOrientation( US_IMG_ORIENT_MF ) );
@@ -861,10 +854,10 @@ PlusStatus vtkPlusMetaImageSequenceIO::AppendImagesToHeader()
861854
}
862855

863856
// Write frame fields (Seq_Frame0000_... = ...)
864-
for ( unsigned int frameNumber = CurrentFrameOffset; frameNumber < this->TrackedFrameList->GetNumberOfTrackedFrames() + CurrentFrameOffset; frameNumber++ )
857+
for ( unsigned int frameNumber = this->CurrentFrameOffset; frameNumber < this->TrackedFrameList->GetNumberOfTrackedFrames() + this->CurrentFrameOffset; frameNumber++ )
865858
{
866859
LOG_DEBUG( "Writing frame " << frameNumber );
867-
unsigned int adjustedFrameNumber = frameNumber - CurrentFrameOffset;
860+
unsigned int adjustedFrameNumber = frameNumber - this->CurrentFrameOffset;
868861
PlusTrackedFrame* trackedFrame = this->TrackedFrameList->GetTrackedFrame( adjustedFrameNumber );
869862

870863
std::ostringstream frameIndexStr;
@@ -1262,16 +1255,15 @@ PlusStatus vtkPlusMetaImageSequenceIO::UpdateFieldInImageHeader( const char* fie
12621255
newLineStr << name << " = " << GetCustomString( name.c_str() );
12631256

12641257
// need to add padding whitespace characters to fully replace the old line
1265-
int paddingCharactersNeeded = SEQMETA_FIELD_PADDED_LINE_LENGTH - newLineStr.str().size();
1266-
for ( int i = 0; i < paddingCharactersNeeded; i++ )
1258+
int paddingCharactersNeeded = line.length() - newLineStr.str().size();
1259+
if (paddingCharactersNeeded < 0)
12671260
{
1268-
newLineStr << " ";
1261+
LOG_ERROR("Cannot update line in image header (the new string '" << newLineStr.str() << "' is longer than the current string '" << line << "')");
1262+
return PLUS_FAIL;
12691263
}
1270-
1271-
if ( newLineStr.str().length() != line.length() )
1264+
for ( int i = 0; i < paddingCharactersNeeded; i++ )
12721265
{
1273-
LOG_ERROR( "Cannot update line in image header (the new string '" << newLineStr.str() << "' is longer than the current string '" << line << "')" );
1274-
return PLUS_FAIL;
1266+
newLineStr << " ";
12751267
}
12761268

12771269
// rewind to file pointer the first character of the line
@@ -1387,7 +1379,7 @@ PlusStatus vtkPlusMetaImageSequenceIO::SetFileName( const std::string& aFilename
13871379
}
13881380

13891381
//----------------------------------------------------------------------------
1390-
PlusStatus vtkPlusMetaImageSequenceIO::GenerateFrameSizeCustomStrings( int numberOfFrames, bool isData3D )
1382+
PlusStatus vtkPlusMetaImageSequenceIO::UpdateDimensionsCustomStrings( int numberOfFrames, bool isData3D )
13911383
{
13921384
if ( this->EnableImageDataWrite && this->TrackedFrameList->IsContainingValidImageData() )
13931385
{

PlusLib/src/PlusCommon/IO/vtkPlusMetaImageSequenceIO.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class vtkPlusCommonExport vtkPlusMetaImageSequenceIO : public vtkPlusSequenceIOB
3939
/param numberOfFrames the new number of frames to write
4040
/param isData3D is the data 3D or 2D?
4141
*/
42-
virtual PlusStatus GenerateFrameSizeCustomStrings(int numberOfFrames, bool isData3D);
42+
virtual PlusStatus UpdateDimensionsCustomStrings(int numberOfFrames, bool isData3D);
4343

4444
/*!
4545
Append the frames in tracked frame list to the header, if the onlyTrackerData flag is true it will not save
@@ -88,7 +88,7 @@ class vtkPlusCommonExport vtkPlusMetaImageSequenceIO : public vtkPlusSequenceIOB
8888
virtual PlusStatus PrepareImageFile();
8989

9090
/*! Write all the fields to the metaimage file header */
91-
virtual PlusStatus OpenImageHeader();
91+
virtual PlusStatus WriteInitialImageHeader();
9292

9393
/*!
9494
Writes the compressed pixel data directly into file.

PlusLib/src/PlusCommon/IO/vtkPlusNrrdSequenceIO.cxx

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ bool vtkPlusNrrdSequenceIO::CanWriteFile( const std::string& filename )
565565
//----------------------------------------------------------------------------
566566
/** Writes the spacing and dimensions of the image.
567567
* Assumes SetFileName has been called with a valid file name. */
568-
PlusStatus vtkPlusNrrdSequenceIO::OpenImageHeader()
568+
PlusStatus vtkPlusNrrdSequenceIO::WriteInitialImageHeader()
569569
{
570570
if( this->TrackedFrameList->GetNumberOfTrackedFrames() == 0 )
571571
{
@@ -575,7 +575,7 @@ PlusStatus vtkPlusNrrdSequenceIO::OpenImageHeader()
575575

576576
// First, is this 2D or 3D?
577577
bool isData3D = ( this->TrackedFrameList->GetTrackedFrame( 0 )->GetFrameSize()[2] > 1 );
578-
bool isDataTimeSeries = this->TrackedFrameList->GetNumberOfTrackedFrames() > 1;
578+
bool isDataTimeSeries = this->IsDataTimeSeries; // don't compute it from the number of frames because we may still have only one frame but acquire more frames later
579579
this->NumberOfScalarComponents = this->TrackedFrameList->GetTrackedFrame( 0 )->GetNumberOfScalarComponents();
580580

581581
// Override fields
@@ -589,21 +589,10 @@ PlusStatus vtkPlusNrrdSequenceIO::OpenImageHeader()
589589
this->NumberOfDimensions++;
590590
}
591591

592-
{
593-
std::stringstream ss;
594-
ss << this->NumberOfDimensions;
595-
SetCustomString( "dimension", ss.str() );
596-
}
592+
SetCustomString("dimension", this->NumberOfDimensions);
597593

598594
// CompressedData
599-
if ( GetUseCompression() )
600-
{
601-
SetCustomString( "encoding", "gz" );
602-
}
603-
else
604-
{
605-
SetCustomString( "encoding", "raw" );
606-
}
595+
SetCustomString("encoding", GetUseCompression() ? "gz" : "raw");
607596

608597
unsigned int frameSize[3] = {0, 0, 0};
609598
if( this->EnableImageDataWrite )
@@ -645,7 +634,7 @@ PlusStatus vtkPlusNrrdSequenceIO::OpenImageHeader()
645634
SetCustomString( "endian", "little" );
646635

647636
// Update sizes field in header
648-
this->GenerateFrameSizeCustomStrings( this->TrackedFrameList->GetNumberOfTrackedFrames(), isData3D );
637+
this->UpdateDimensionsCustomStrings( this->TrackedFrameList->GetNumberOfTrackedFrames(), isData3D );
649638

650639
// PixelType
651640
if ( this->TrackedFrameList->IsContainingValidImageData() )
@@ -667,12 +656,7 @@ PlusStatus vtkPlusNrrdSequenceIO::OpenImageHeader()
667656
// "This (or "space dimension") has to precede the other orientation-related fields, because it determines
668657
// how many components there are in the vectors of the space origin, space directions, and measurement frame fields."
669658
int numSpaceDimensions = isData3D ? 3 : 2;
670-
671-
{
672-
std::stringstream ss;
673-
ss << numSpaceDimensions;
674-
SetCustomString( "space dimension", ss.str() );
675-
}
659+
SetCustomString("space dimension", numSpaceDimensions);
676660

677661
// Generate the origin string, such as (0,0) or (0,0,0)
678662
std::stringstream originStr;
@@ -1225,16 +1209,15 @@ PlusStatus vtkPlusNrrdSequenceIO::UpdateFieldInImageHeader( const char* fieldNam
12251209
newLineStr << name << ":" << ( isKeyValue ? "=" : " " ) << GetCustomString( name.c_str() );
12261210

12271211
// need to add padding whitespace characters to fully replace the old line
1228-
int paddingCharactersNeeded = SEQUENCE_FIELD_PADDED_LINE_LENGTH - newLineStr.str().size();
1229-
for ( int i = 0; i < paddingCharactersNeeded; i++ )
1212+
int paddingCharactersNeeded = line.length() - newLineStr.str().size();
1213+
if (paddingCharactersNeeded < 0)
12301214
{
1231-
newLineStr << " ";
1215+
LOG_ERROR("Cannot update line in image header (the new string '" << newLineStr.str() << "' is longer than the current string '" << line << "')");
1216+
return PLUS_FAIL;
12321217
}
1233-
1234-
if ( newLineStr.str().length() != line.length() )
1218+
for ( int i = 0; i < paddingCharactersNeeded; i++ )
12351219
{
1236-
LOG_ERROR( "Cannot update line in image header (the new string '" << newLineStr.str() << "' is longer than the current string '" << line << "')" );
1237-
return PLUS_FAIL;
1220+
newLineStr << " ";
12381221
}
12391222

12401223
// rewind to file pointer the first character of the line
@@ -1314,7 +1297,7 @@ PlusStatus vtkPlusNrrdSequenceIO::SetFileName( const std::string& aFilename )
13141297
}
13151298

13161299
//----------------------------------------------------------------------------
1317-
PlusStatus vtkPlusNrrdSequenceIO::GenerateFrameSizeCustomStrings( int numberOfFrames, bool isData3D )
1300+
PlusStatus vtkPlusNrrdSequenceIO::UpdateDimensionsCustomStrings(int numberOfFrames, bool isData3D)
13181301
{
13191302
if ( this->EnableImageDataWrite && this->TrackedFrameList->IsContainingValidImageData() )
13201303
{

PlusLib/src/PlusCommon/IO/vtkPlusNrrdSequenceIO.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class vtkPlusCommonExport vtkPlusNrrdSequenceIO : public vtkPlusSequenceIOBase
5151
/param dimensions number of dimensions in the data
5252
/param isData3D is the data 3D or 2D?
5353
*/
54-
virtual PlusStatus GenerateFrameSizeCustomStrings( int numberOfFrames, bool isData3D );
54+
virtual PlusStatus UpdateDimensionsCustomStrings( int numberOfFrames, bool isData3D );
5555

5656
/*!
5757
Append the frames in tracked frame list to the header, if the onlyTrackerData flag is true it will not save
@@ -100,7 +100,7 @@ class vtkPlusCommonExport vtkPlusNrrdSequenceIO : public vtkPlusSequenceIOBase
100100
virtual PlusStatus PrepareImageFile();
101101

102102
/*! Write all the fields to the image file header */
103-
virtual PlusStatus OpenImageHeader();
103+
virtual PlusStatus WriteInitialImageHeader();
104104

105105
/*!
106106
Writes the compressed pixel data directly into file.

PlusLib/src/PlusCommon/IO/vtkPlusSequenceIOBase.cxx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ vtkPlusSequenceIOBase::vtkPlusSequenceIOBase()
3333
, EnableImageDataWrite( true )
3434
, PixelType( VTK_VOID )
3535
, NumberOfScalarComponents( 1 )
36+
, IsDataTimeSeries(true)
3637
, NumberOfDimensions( 4 )
3738
, CurrentFrameOffset( 0 )
3839
, TotalBytesWritten( 0 )
@@ -139,6 +140,20 @@ bool vtkPlusSequenceIOBase::SetCustomString( const std::string& fieldName, const
139140
return PLUS_SUCCESS;
140141
}
141142

143+
//----------------------------------------------------------------------------
144+
bool vtkPlusSequenceIOBase::SetCustomString(const std::string& fieldName, int fieldValue)
145+
{
146+
if (fieldName.empty())
147+
{
148+
LOG_ERROR("Invalid field name");
149+
return PLUS_FAIL;
150+
}
151+
std::stringstream ss;
152+
ss << fieldValue;
153+
this->TrackedFrameList->SetCustomString(fieldName, ss.str());
154+
return PLUS_SUCCESS;
155+
}
156+
142157
//----------------------------------------------------------------------------
143158
const char* vtkPlusSequenceIOBase::GetCustomString( const char* fieldName )
144159
{
@@ -223,7 +238,7 @@ PlusStatus vtkPlusSequenceIOBase::PrepareHeader()
223238
this->TempImageFileName = tempFilename;
224239
}
225240

226-
if ( this->OpenImageHeader() != PLUS_SUCCESS )
241+
if ( this->WriteInitialImageHeader() != PLUS_SUCCESS )
227242
{
228243
return PLUS_FAIL;
229244
}
@@ -293,9 +308,9 @@ PlusStatus vtkPlusSequenceIOBase::Close()
293308
this->TempHeaderFileName.clear();
294309
this->TempImageFileName.clear();
295310

296-
CurrentFrameOffset = 0;
297-
TotalBytesWritten = 0;
298-
CompressedBytesWritten = 0;
311+
this->CurrentFrameOffset = 0;
312+
this->TotalBytesWritten = 0;
313+
this->CompressedBytesWritten = 0;
299314

300315
return PLUS_SUCCESS;
301316
}
@@ -372,7 +387,7 @@ PlusStatus vtkPlusSequenceIOBase::WriteImages()
372387

373388
if( result == PLUS_SUCCESS )
374389
{
375-
CurrentFrameOffset += TrackedFrameList->GetNumberOfTrackedFrames();
390+
this->CurrentFrameOffset += this->TrackedFrameList->GetNumberOfTrackedFrames();
376391
}
377392
return result;
378393
}
@@ -444,8 +459,8 @@ PlusStatus vtkPlusSequenceIOBase::Discard()
444459
this->TempHeaderFileName.clear();
445460
this->TempImageFileName.clear();
446461

447-
CurrentFrameOffset = 0;
448-
TotalBytesWritten = 0;
462+
this->CurrentFrameOffset = 0;
463+
this->TotalBytesWritten = 0;
449464

450465
return PLUS_SUCCESS;
451466
}

PlusLib/src/PlusCommon/IO/vtkPlusSequenceIOBase.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class vtkPlusCommonExport vtkPlusSequenceIOBase : public vtkObject
8585
/param numberOfFrames the new number of frames to write
8686
/param isData3D is the data 3D or 2D?
8787
*/
88-
virtual PlusStatus GenerateFrameSizeCustomStrings( int numberOfFrames, bool isData3D ) = 0;
88+
virtual PlusStatus UpdateDimensionsCustomStrings( int numberOfFrames, bool isData3D ) = 0;
8989

9090
/*! Update a field in the image header with its current value */
9191
virtual PlusStatus UpdateFieldInImageHeader( const char* fieldName ) = 0;
@@ -120,6 +120,13 @@ class vtkPlusCommonExport vtkPlusSequenceIOBase : public vtkObject
120120
/*! Flag to enable/disable compression of image data */
121121
vtkBooleanMacro( UseCompression, bool );
122122

123+
/*! Flag to indicate that there is a time dimension */
124+
vtkGetMacro(IsDataTimeSeries, bool);
125+
/*! Flag to indicate that there is a time dimension */
126+
vtkSetMacro(IsDataTimeSeries, bool);
127+
/*! Flag to indicate that there is a time dimension */
128+
vtkBooleanMacro(IsDataTimeSeries, bool);
129+
123130
/*! Return the dimensions of the sequence */
124131
vtkGetVector4Macro( Dimensions, unsigned int );
125132

@@ -138,7 +145,7 @@ class vtkPlusCommonExport vtkPlusSequenceIOBase : public vtkObject
138145
virtual PlusStatus ReadImagePixels() = 0;
139146

140147
/*! Write all the fields to the sequence file header */
141-
virtual PlusStatus OpenImageHeader() = 0;
148+
virtual PlusStatus WriteInitialImageHeader() = 0;
142149

143150
/*! Prepare the image file for writing */
144151
virtual PlusStatus PrepareImageFile() = 0;
@@ -174,6 +181,7 @@ class vtkPlusCommonExport vtkPlusSequenceIOBase : public vtkObject
174181
/*! Get a custom string field value for a specific frame */
175182
bool SetCustomString( const char* fieldName, const char* fieldValue );
176183
bool SetCustomString( const std::string& fieldName, const std::string& fieldValue );
184+
bool SetCustomString(const std::string& fieldName, int fieldValue);
177185

178186
/*! Get a custom string field value (global, not for a specific frame) */
179187
const char* GetCustomString( const char* fieldName );
@@ -213,6 +221,8 @@ class vtkPlusCommonExport vtkPlusSequenceIOBase : public vtkObject
213221
PlusCommon::VTKScalarPixelType PixelType;
214222
/*! Number of components (or channels) */
215223
int NumberOfScalarComponents;
224+
/*! True if there is a time dimension */
225+
bool IsDataTimeSeries;
216226
/*! Number of image dimensions. Only 2 (single frame) or 3 (sequence of frames) or 4 (sequence of volumes) are supported. */
217227
int NumberOfDimensions;
218228
/*! Frame size (first three elements) and number of frames (last element) */

PlusLib/src/PlusCommon/vtkPlusTrackedFrameList.cxx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,10 @@ PlusStatus vtkPlusTrackedFrameList::SaveToSequenceMetafile( const std::string& f
462462
writer->SetImageOrientationInFile( orientationInFile );
463463
writer->SetTrackedFrameList( this );
464464
writer->SetEnableImageDataWrite( enableImageDataWrite );
465+
if (this->GetNumberOfTrackedFrames() == 1)
466+
{
467+
writer->IsDataTimeSeriesOff();
468+
}
465469
if ( writer->Write() != PLUS_SUCCESS )
466470
{
467471
LOG_ERROR( "Couldn't write sequence metafile: " << filename );
@@ -507,6 +511,10 @@ PlusStatus vtkPlusTrackedFrameList::SaveToNrrdFile( const std::string& filename,
507511
writer->SetImageOrientationInFile( orientationInFile );
508512
writer->SetTrackedFrameList( this );
509513
writer->SetEnableImageDataWrite( enableImageDataWrite );
514+
if (this->GetNumberOfTrackedFrames() == 1)
515+
{
516+
writer->IsDataTimeSeriesOff();
517+
}
510518
if ( writer->Write() != PLUS_SUCCESS )
511519
{
512520
LOG_ERROR( "Couldn't write Nrrd file: " << filename );

PlusLib/src/PlusDataCollection/VirtualDevices/vtkPlusVirtualDiscCapture.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ PlusStatus vtkPlusVirtualDiscCapture::CloseFile( const char* aFilename /* = NULL
226226
this->WriteFrames( true );
227227
}
228228

229-
this->Writer->GenerateFrameSizeCustomStrings( this->TotalFramesRecorded, this->GetIsData3D() );
229+
this->Writer->UpdateDimensionsCustomStrings(this->TotalFramesRecorded, this->GetIsData3D());
230230
this->Writer->UpdateFieldInImageHeader( this->Writer->GetDimensionSizeString() );
231231
this->Writer->UpdateFieldInImageHeader( this->Writer->GetDimensionKindsString() );
232232
this->Writer->FinalizeHeader();

0 commit comments

Comments
 (0)