Я скачал AffineTranformation из Wiki Example и изменил его, чтобы связать два файла DICOM. Я строю это успешно. Но когда я запускаю это. У него есть мессенджер ошибки:
terminate called after throwing an instance of 'itk::ExceptionObject'
what(): /usr/local/include/ITK-4.4/itkImageFileWriter.hxx:123:
itk::ERROR: ImageFileWriter(0x9808fd8): No filename was specified
Aborted (core dumped)
Это мой код для редактирования. Пожалуйста, помогите мне отредактировать это. Я использую новейшую версию ITK 4.3.1 для Linux
#include "itkCastImageFilter.h"``
#include "itkEllipseSpatialObject.h"#include "itkImage.h"#include "itkImageRegistrationMethod.h"#include "itkLinearInterpolateImageFunction.h"#include "itkImageFileReader.h"#include "itkImageFileWriter.h"#include "itkMeanSquaresImageToImageMetric.h"#include "itkRegularStepGradientDescentOptimizer.h"#include "itkResampleImageFilter.h"#include "itkRescaleIntensityImageFilter.h"#include "itkSpatialObjectToImageFilter.h"#include "itkAffineTransform.h"#include "itkGDCMImageIO.h"// Software Guide : EndCodeSnippet
#include <list>
#include <fstream>
const unsigned int Dimension = 2;
typedef unsigned char PixelType;
typedef itk::Image< PixelType, Dimension > ImageType;
static void CreateEllipseImage(ImageType::Pointer image);
static void CreateSphereImage(ImageType::Pointer image);
int main(int, char *[] )
{
// The transform that will map the fixed image into the moving image.
typedef itk::AffineTransform< double, Dimension > TransformType;
// An optimizer is required to explore the parameter space of the transform
// in search of optimal values of the metric.
typedef itk::RegularStepGradientDescentOptimizer OptimizerType;
// The metric will compare how well the two images match each other. Metric
// types are usually parameterized by the image types as it can be seen in
// the following type declaration.
typedef itk::MeanSquaresImageToImageMetric<
ImageType,
ImageType > MetricType;
// Finally, the type of the interpolator is declared. The interpolator will
// evaluate the intensities of the moving image at non-grid positions.
typedef itk:: LinearInterpolateImageFunction<
ImageType,
double > InterpolatorType;
// The registration method type is instantiated using the types of the
// fixed and moving images. This class is responsible for interconnecting
// all the components that we have described so far.
typedef itk::ImageRegistrationMethod<
ImageType,
ImageType > RegistrationType;
// Create components
MetricType::Pointer metric = MetricType::New();
TransformType::Pointer transform = TransformType::New();
OptimizerType::Pointer optimizer = OptimizerType::New();
InterpolatorType::Pointer interpolator = InterpolatorType::New();
RegistrationType::Pointer registration = RegistrationType::New();
// Each component is now connected to the instance of the registration method.
registration->SetMetric( metric );
registration->SetOptimizer( optimizer );
registration->SetTransform( transform );
registration->SetInterpolator( interpolator );
// Write the two synthetic inputs
typedef itk::Image< PixelType, Dimension > FixedImageType;
typedef itk::Image< PixelType, Dimension > MovingImageType;
// Software Guide : EndCodeSnippet
// Set up the file readers
typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType;
typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType;
FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New();
MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New();
fixedImageReader->SetFileName("fix.dcm" );
movingImageReader->SetFileName( "mov.dcm" );
typedef itk::ImageFileWriter< ImageType > WriterType;
WriterType::Pointer fixedWriter = WriterType::New();
//ixedWriter->SetFileName("fixed.png");
fixedWriter->SetInput( fixedImageReader->GetOutput());
fixedWriter->Update();
WriterType::Pointer movingWriter = WriterType::New();
// movingWriter->SetFileName("moving.png");
movingWriter->SetInput( movingImageReader->GetOutput());
movingWriter->Update();
// Set the registration inputs
registration->SetFixedImage(fixedImageReader->GetOutput());
registration->SetMovingImage(movingImageReader->GetOutput());
registration->SetFixedImageRegion(
fixedImageReader->GetOutput()->GetLargestPossibleRegion() );
// Initialize the transform
typedef RegistrationType::ParametersType ParametersType;
ParametersType initialParameters( transform->GetNumberOfParameters() );
// rotation matrix
initialParameters[0] = 1.0; // R(0,0)
initialParameters[1] = 0.0; // R(0,1)
initialParameters[2] = 0.0; // R(1,0)
initialParameters[3] = 1.0; // R(1,1)
// translation vector
initialParameters[4] = 0.0;
initialParameters[5] = 0.0;
registration->SetInitialTransformParameters( initialParameters );
optimizer->SetMaximumStepLength( .1 ); // If this is set too high, you will get a
//"itk::ERROR: MeanSquaresImageToImageMetric(0xa27ce70): Too many samples map outside moving image buffer: 1818 / 10000" error
optimizer->SetMinimumStepLength( 0.01 );
// Set a stopping criterion
optimizer->SetNumberOfIterations( 200 );
// Connect an observer
//CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New();
//optimizer->AddObserver( itk::IterationEvent(), observer );
try
{
registration->Update();
}
catch( itk::ExceptionObject & err )
{
std::cerr << "ExceptionObject caught !" << std::endl;
std::cerr << err << std::endl;
return EXIT_FAILURE;
}
// The result of the registration process is an array of parameters that
// defines the spatial transformation in an unique way. This final result is
// obtained using the \code{GetLastTransformParameters()} method.
ParametersType finalParameters = registration->GetLastTransformParameters();
std::cout << "Final parameters: " << finalParameters << std::endl;
// The value of the image metric corresponding to the last set of parameters
// can be obtained with the \code{GetValue()} method of the optimizer.
const double bestValue = optimizer->GetValue();
// Print out results
//
std::cout << "Result = " << std::endl;
std::cout << " Metric value = " << bestValue << std::endl;
// It is common, as the last step of a registration task, to use the
// resulting transform to map the moving image into the fixed image space.
// This is easily done with the \doxygen{ResampleImageFilter}.
typedef itk::ResampleImageFilter<
ImageType,
ImageType > ResampleFilterType;
ResampleFilterType::Pointer resampler = ResampleFilterType::New();
resampler->SetInput( movingImageReader->GetOutput());
// The Transform that is produced as output of the Registration method is
// also passed as input to the resampling filter. Note the use of the
// methods \code{GetOutput()} and \code{Get()}. This combination is needed
// here because the registration method acts as a filter whose output is a
// transform decorated in the form of a \doxygen{DataObject}. For details in
// this construction you may want to read the documentation of the
// \doxygen{DataObjectDecorator}.
resampler->SetTransform( registration->GetOutput()->Get() );
// As described in Section \ref{sec:ResampleImageFilter}, the
// ResampleImageFilter requires additional parameters to be specified, in
// particular, the spacing, origin and size of the output image. The default
// pixel value is also set to a distinct gray level in order to highlight
// the regions that are mapped outside of the moving image.
resampler->SetSize( fixedImageReader->GetOutput()->GetLargestPossibleRegion().GetSize() );
resampler->SetOutputOrigin( fixedImageReader->GetOutput()->GetOrigin() );
resampler->SetOutputSpacing( fixedImageReader->GetOutput()->GetSpacing() );
resampler->SetOutputDirection( fixedImageReader->GetOutput()->GetDirection() );
resampler->SetDefaultPixelValue( 100 );
// The output of the filter is passed to a writer that will store the
// image in a file. An \doxygen{CastImageFilter} is used to convert the
// pixel type of the resampled image to the final type used by the
// writer. The cast and writer filters are instantiated below.
typedef unsigned char OutputPixelType;
typedef itk::Image< OutputPixelType, Dimension > OutputImageType;
typedef itk::CastImageFilter<
ImageType,
ImageType > CastFilterType;
WriterType::Pointer writer = WriterType::New();
CastFilterType::Pointer caster = CastFilterType::New();
writer->SetFileName("output.png");
caster->SetInput( resampler->GetOutput() );
writer->SetInput( caster->GetOutput() );
writer->Update();
return EXIT_SUCCESS;
}
Сообщение об ошибке No filename was specified
и действительно призывы к SetFileName()
были закомментированы:
WriterType::Pointer fixedWriter = WriterType::New();
// fixedWriter->SetFileName("fixed.png");
WriterType::Pointer movingWriter = WriterType::New();
// movingWriter->SetFileName("moving.png");
Вы просто не можете читать файлы dicom, такие как чтение другого формата файла, такого как «.nrrd» на заводе. ITK использует GDCM для работы с dicom IO. Взгляните на это http://www.itk.org/Wiki/ITK/Examples/DICOM/ResampleDICOM