我是ITK和C ++的新手,目前正在为图像配准算法设置测试程序。在我的消息中,我将讲述我在使用ITK术语时所做的具体细节。但是,我希望任何有经验的C ++程序员都能够在不了解ITK细节的情况下告诉我的代码有什么问题,因为我认为我在引用/解除引用时只是做错了。这里要跟踪的事情(下面将详细解释)是MetaDataContainer类型的变量,在所有函数中都称为metaData。如果任何ITK特定信息让您感到困惑,请询问更多详细信息,但我不想将此原始信息写得太久。无论如何,这里是:
我必须在程序执行中多次读取和写入dicom-images,因此我不是每次都执行读/写过程的所有步骤,而是决定为它们编写单独的函数。由于我必须使用读取过程中的一些数据,例如输出中的MetaDataDictionaryArray,readDicom函数(以及另一个函数preregistrationOperations)返回一个元组:
typedef std::tuple< ImageType::Pointer, MetaDataContainer, FileNamesContainer > ImageMetaOutputTuple;
要注意的另一个重要的typedef是MetaDataContainer,它本身就是一个指向DictionaryRawPointer-vector的指针。来自ItkImageSeriesReader.h:
typedef MetaDataDictionary DictionaryType;
typedef MetaDataDictionary * DictionaryRawPointer;
typedef std::vector< DictionaryRawPointer > DictionaryArrayType;
typedef const DictionaryArrayType * DictionaryArrayRawPointer;
在我自己的头文件中,feir.h:
typedef itk::ImageSeriesWriter< ImageType, Image2DType >::DictionaryArrayRawPointer MetaDataContainer;
其他类型与用于Dicom处理的ITK示例相同。我的程序的粗略布局如下所示。
此程序在writeDicom函数中崩溃,但错误“...矢量下标超出范围”。我已经将错误缩小到与MetaDataDictionaryArray有关。当首次读取dicom时,它的大小是例如。 64(系列中的文件数),但当它返回到preRegistrationOperations时,它的大小突然为0,然后将这个零大小的容器传递给崩溃的writeDicom。
编辑:崩溃本身发生在seriesWriter->Update()
- 行。
我试图通过使用MetaDataContainer指针解决此问题,但问题仍然存在。我可能会补充一点,我对C ++也很陌生(更多的是物理学家而不是程序员)。有人可以帮助我吗?它应该很简单,从readDicom返回一个元组内的MetaDataContainer,在preRegistrationOperations中解压缩,然后将它传递给writeDicom,但无论我如何尝试,我都无法使它工作。
祝你好运, 的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 );
…
}
答案 0 :(得分:0)
可能是GetMetaDataDictionaryArray只返回系列阅读器成员的原始指针,但是当你从readDicom退出时,阅读器会退出范围。在这种情况下,我会期望你有更多的段错误,但也许这是一个值得研究的方向。 您可以在函数中添加4个额外的参数来存储结果,而不是返回元组(为了便于调试)。
触摸字典它总是很讨厌,这里是一个例子http://www.itk.org/Wiki/ITK/Examples/DICOM/ResampleDICOM(但是在这里他们逐片地读取字典)。您确定需要更新吗?某些字段将由dicom writer自动更新(例如方向),无论如何都不能强制它们。