简体   繁体   English

指针作为ITK / C ++中的函数参数-无法使其正常工作

[英]Pointer as function argument in ITK/C++ - can't get it working

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. 我是ITK和C ++的新手,目前正在为图像配准算法设置测试程序。 In my message I will tell the specifics of what I'm doing in using ITK-terminology. 在我的消息中,我将详细说明我在使用ITK术语时正在做的事情。 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. 但是,我希望任何有经验的C ++程序员都应该能够在不理解ITK细节的情况下告诉我代码有什么问题,因为我认为我在引用/解引用中所做的只是错误。 The thing to keep track of here (explained in more detail below) is the MetaDataContainer-type variable, called metaData in all functions. 此处要跟踪的内容(下面将详细说明)是MetaDataContainer类型的变量,在所有函数中均称为metaData。 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. 如果有任何ITK方面的细节使您感到困惑,请询问更多详细信息,但是我不想让此原始消息太长。 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. 我将不得不在程序执行过程中多次读写dicom图像,因此,我决定不为它们编写单独的函数,而不必每次都执行读/写过程的所有步骤。 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: 由于我必须使用读取过程中的一些数据,例如输出中的MetaDataDictionaryArray,因此readDicom函数(以及另一个函数preregistrationOperations)返回一个元组:

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. 要注意的另一个重要的typedef是MetaDataContainer,它本身是指向DictionaryRawPointer-vector的指针。 From ItkImageSeriesReader.h: 从ItkImageSeriesReader.h:

typedef MetaDataDictionary                  DictionaryType;
typedef MetaDataDictionary *                DictionaryRawPointer;
typedef std::vector< DictionaryRawPointer > DictionaryArrayType;
typedef const DictionaryArrayType *         DictionaryArrayRawPointer;

In my own header-file, feir.h: 在我自己的头文件feir.h中:

typedef itk::ImageSeriesWriter< ImageType, Image2DType >::DictionaryArrayRawPointer  MetaDataContainer;

The other types are the same as in the ITK-examples for Dicom-handling. 其他类型与Dicom处理的ITK示例相同。 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”. 但是,该程序在writeDicom函数中崩溃,并显示错误“…向量下标超出范围”。 I have narrowed the error down to having to do with the MetaDataDictionaryArray. 我将错误的范围缩小到与MetaDataDictionaryArray有关。 Its size when the dicoms are first read in reaDicom is eg 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. 首次在reaDicom中读取dicoms时,其大小为64(序列中的文件数),但是当将其返回到preRegistrationOperations时,其大小突然为0,然后通过此零大小的容器崩溃的writeDicom。

EDIT: the crash itself happens on the seriesWriter->Update() -line. 编辑:崩溃本身发生在seriesWriter->Update()

I have tried to get around this problem by using MetaDataContainer-pointers instead, but the problem persists. 我试图通过改用MetaDataContainer-pointers来解决此问题,但问题仍然存在。 I might add that I'm quite new to C++ too (more of a physicist than a programmer). 我可能还会补充说,我对C ++也很陌生(更多是物理学家,而不是程序员)。 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. 从readDicom的元组中返回MetaDataContainer,将其解压缩到preRegistrationOperations中,然后将其传递给writeDicom应该足够简单,但是无论如何尝试,我都无法使其正常工作。

Best regards, Mikael 最好的问候,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 );       
   …
}

It could be that GetMetaDataDictionaryArray just returns the raw pointer of a member of the series reader, but when you exit from readDicom the reader goes out scope. 可能是GetMetaDataDictionaryArray仅返回系列阅读器成员的原始指针,但是当您从readDicom退出时,阅读器将超出范围。 I would expect more that you had a segfault in this case, but maybe it's a direction to look into. 我希望您在这种情况下遇到段错误,但这可能是研究的方向。 Instead of returning a tuple, you could add 4 extra arguments in your function where to store the result (for an easier debugging). 除了返回元组,您还可以在函数中添加4个额外的参数来存储结果(以便于调试)。

Touching the dictionary it's always nasty, here is an example http://www.itk.org/Wiki/ITK/Examples/DICOM/ResampleDICOM (but here they read the dictionary slice by slice). 触摸字典总是很讨厌,这是一个示例http://www.itk.org/Wiki/ITK/Examples/DICOM/ResampleDICOM (但在这里他们逐片阅读字典)。 Are you sure that you need to update it? 您确定需要更新吗? Some fields will be automatically updated by the dicom writer (for example orientation), you can not force them anyway. dicom编写器会自动更新某些字段(例如,方向),无论如何您都不能强制执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM