I’m new to both ITK and C++, and am currently in the process of setting up a testing program for an image registration algorithm. In my message I will tell the specifics of what I'm doing in using ITK-terminology. However, I expect that any experienced C++-programmer should be able to tell what's wrong with my code without understanding the specifics of ITK, since I think I'm just doing something wrong in my referencing/dereferencing. The thing to keep track of here (explained in more detail below) is the MetaDataContainer-type variable, called metaData in all functions. If any of the ITK-specifics confuse you, please ask for more details, but I didn't want to make this original message too long. Anyway, here goes:
I will have to read and write dicom-images quite a few times within the program execution, so instead of doing all the steps of the read/write processes every time, I decided to write separate functions for them. Since I have to use some data from the reading process, such as the MetaDataDictionaryArray in the output as well, the readDicom-function (as well as another function, preregistrationOperations) returns a tuple:
typedef std::tuple< ImageType::Pointer, MetaDataContainer, FileNamesContainer > ImageMetaOutputTuple;
The other important typedef to be aware of is the MetaDataContainer, which is itself a pointer to a DictionaryRawPointer-vector. From ItkImageSeriesReader.h:
typedef MetaDataDictionary DictionaryType;
typedef MetaDataDictionary * DictionaryRawPointer;
typedef std::vector< DictionaryRawPointer > DictionaryArrayType;
typedef const DictionaryArrayType * DictionaryArrayRawPointer;
In my own header-file, feir.h:
typedef itk::ImageSeriesWriter< ImageType, Image2DType >::DictionaryArrayRawPointer MetaDataContainer;
The other types are the same as in the ITK-examples for Dicom-handling. The rough layout of my program is seen below.
This program crashes in the writeDicom-function however, with the error “…vector subscript out of range”. I have narrowed the error down to having to do with the MetaDataDictionaryArray. Its size when the dicoms are first read in reaDicom is e.g. 64 (the number of files in the series), but when it is returned to the preRegistrationOperations, its size is suddenly 0, and it is this zero-sized container that is then passed to writeDicom which crashes.
EDIT: the crash itself happens on the seriesWriter->Update()
-line.
I have tried to get around this problem by using MetaDataContainer-pointers instead, but the problem persists. I might add that I’m quite new to C++ too (more of a physicist than a programmer). Can anybody help me in this? It should be simple enough to return a MetaDataContainer within a tuple from readDicom, unpack it in preRegistrationOperations, and pass it to writeDicom, but no matter how I try I can’t get it to work.
Best regards, Mikael
ImageMetaOutputTuple preRegistrationOperations( std::string inputDir, std::string outputDir, std::string seriesNumber, bool preparationsDone = false, bool verbose = true )
{
// No output verbose if operations have already been done
if (preparationsDone) verbose = false;
// Read input-Dicoms
ImageType::Pointer image;
MetaDataContainer metaData;
FileNamesContainer outputFilenames;
ImageMetaOutputTuple returnTuple = readDicom( inputDir, outputDir, seriesNumber, verbose );
std::tie (image, metaData, outputFilenames) = returnTuple;
// Pass image and directory and filename information to writeDicom and write into outputDir
if (!preparationsDone) {
try {
int resultCode = writeDicom( image, outputDir, outputFilenames, metaData );
}
catch (itk::ExceptionObject &ex) {
std::cout << "Exception caught in writeDICOM:" << std::endl;
std::cout << ex << std::endl;
}
}
return returnTuple;
}
-
int writeDicom ( ImageType::Pointer image, std::string inputDir, FileNamesContainer filenames, MetaDataContainer metaData )
{
…
seriesWriter->SetMetaDataDictionaryArray( metaData );
try {
seriesWriter->Update();
return 0;
}
catch {
...
}
…
}
-
ImageMetaOutputTuple readDicom ( std::string inputDir, std::string outputDir = "", std::string seriesNumber = "", bool verbose = true)
{
…
image = reader->GetOutput();
files = nameGenerator->GetOutputFileNames();
MetaDataContainer metaData = reader->GetMetaDataDictionaryArray();
…
ImageMetaOutputTuple returnTuple (image, metaData, files);
return returnTuple;
}
-
int main( int argc, char* argv[] )
{
…
ImageType::Pointer moving;
ImageType::Pointer target;
std::tie(moving, std::ignore, std::ignore) = preRegistrationOperations( inputDir, movingDir, movingSeriesNumber, preparationsDone, verbose );
std::tie(target, std::ignore, std::ignore) = preRegistrationOperations( inputDir, targetDir, targetSeriesNumber, preparationsDone, verbose );
…
}
writeDicom
only seems to pass the pointer to another function. Are you sure that the program crashes on that line? – eerorikaseriesWriter->Update();
When I print metaData-Zsize() to the standard output inside readDicom it is 64, which is correct since I have 64 DICOM-images, but when I print its size in the other functions its 0, so something goes wrong when I return it from readDicom. – mkerikssMetaDataContainerPtr
or similar. – eerorika