/*========================================================================= Program: vv http://www.creatis.insa-lyon.fr/rio/vv Authors belong to: - University of LYON http://www.universite-lyon.fr/ - Léon Bérard cancer center http://www.centreleonberard.fr - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the copyright notices for more information. It is distributed under dual licence - BSD See included LICENSE.txt file - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html ===========================================================================**/ // clitk #include "clitkDD.h" // itk include #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageSeriesReader.h" #include "itkImageFileWriter.h" #include "itkRecursiveGaussianImageFilter.h" #include "itkResampleImageFilter.h" #include "itkAffineTransform.h" #include "itkNearestNeighborInterpolateImageFunction.h" #include "itkWindowedSincInterpolateImageFunction.h" #include "itkLinearInterpolateImageFunction.h" #include "itkBSplineInterpolateImageFunction.h" #include "itkBSplineInterpolateImageFunctionWithLUT.h" #include "itkCommand.h" //-------------------------------------------------------------------- template clitk::ResampleImageWithOptionsFilter:: ResampleImageWithOptionsFilter():itk::ImageToImageFilter() { static const unsigned int dim = InputImageType::ImageDimension; this->SetNumberOfRequiredInputs(1); m_OutputIsoSpacing = -1; m_InterpolationType = NearestNeighbor; m_GaussianFilteringEnabled = true; m_BSplineOrder = 3; m_BLUTSamplingFactor = 20; m_LastDimensionIsTime = false; m_Transform = TransformType::New(); if (dim == 4) m_LastDimensionIsTime = true; // by default 4D is 3D+t for(unsigned int i=0; i void clitk::ResampleImageWithOptionsFilter:: SetInput(const InputImageType * image) { // Process object is not const-correct so the const casting is required. this->SetNthInput(0, const_cast(image)); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- template void clitk::ResampleImageWithOptionsFilter:: GenerateInputRequestedRegion() { // call the superclass's implementation of this method Superclass::GenerateInputRequestedRegion(); // get pointers to the input and output InputImagePointer inputPtr = const_cast< InputImageType *>( this->GetInput() ); // Request the entire input image InputImageRegionType inputRegion; inputRegion = inputPtr->GetLargestPossibleRegion(); inputPtr->SetRequestedRegion(inputRegion); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- template void clitk::ResampleImageWithOptionsFilter:: GenerateOutputInformation() { static const unsigned int dim = InputImageType::ImageDimension; // Warning if (!std::numeric_limits::is_signed) { if ((m_InterpolationType == BSpline) || (m_InterpolationType == B_LUT)) { std::cerr << "Warning : input pixel type is not signed, use bspline interpolation at your own risk ..." << std::endl; } } // Get input pointer InputImagePointer input = dynamic_cast(itk::ProcessObject::GetInput(0)); // Perform default implementation Superclass::GenerateOutputInformation(); // Compute sizes InputImageSpacingType inputSpacing = input->GetSpacing(); InputImageSizeType inputSize = input->GetLargestPossibleRegion().GetSize(); if (m_OutputIsoSpacing != -1) { // apply isoSpacing for(unsigned int i=0; iGetOutput(0); // OutputImageRegionType region; m_OutputRegion.SetSize(m_OutputSize); m_OutputRegion.SetIndex(input->GetLargestPossibleRegion().GetIndex()); outputImage->CopyInformation(input); outputImage->SetLargestPossibleRegion(m_OutputRegion); outputImage->SetSpacing(m_OutputSpacing); // Init Gaussian sigma if (m_GaussianSigma[0] != -1) { // Gaussian filter set by user m_GaussianFilteringEnabled = true; } else { if (m_GaussianFilteringEnabled) { // Automated sigma when downsample for(unsigned int i=0; i inputSpacing[i]) { // downsample m_GaussianSigma[i] = 0.5*m_OutputSpacing[i];// / inputSpacing[i]); } else m_GaussianSigma[i] = 0; // will be ignore after } } } if (m_GaussianFilteringEnabled && m_LastDimensionIsTime) { m_GaussianSigma[dim-1] = 0; } } //-------------------------------------------------------------------- //-------------------------------------------------------------------- template void clitk::ResampleImageWithOptionsFilter:: GenerateData() { // Get input pointer InputImagePointer input = dynamic_cast(itk::ProcessObject::GetInput(0)); static const unsigned int dim = InputImageType::ImageDimension; // Create main Resample Image Filter typedef itk::ResampleImageFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); filter->GraftOutput(this->GetOutput()); this->GetOutput()->SetBufferedRegion(this->GetOutput()->GetLargestPossibleRegion()); // Print options if needed if (m_VerboseOptions) { std::cout << "Output Spacing = " << m_OutputSpacing << std::endl << "Output Size = " << m_OutputSize << std::endl << "Gaussian = " << m_GaussianFilteringEnabled << std::endl; if (m_GaussianFilteringEnabled) std::cout << "Sigma = " << m_GaussianSigma << std::endl; std::cout << "Interpol = "; switch (m_InterpolationType) { case NearestNeighbor: std::cout << "NearestNeighbor" << std::endl; break; case Linear: std::cout << "Linear" << std::endl; break; case BSpline: std::cout << "BSpline " << m_BSplineOrder << std::endl; break; case B_LUT: std::cout << "B-LUT " << m_BSplineOrder << " " << m_BLUTSamplingFactor << std::endl; break; case WSINC: std::cout << "Windowed Sinc" << std::endl; break; } #if ITK_VERSION_MAJOR <= 4 std::cout << "Threads = " << this->GetNumberOfThreads() << std::endl; #else std::cout << "Threads = " << this->GetNumberOfWorkUnits() << std::endl; #endif std::cout << "LastDimIsTime = " << m_LastDimensionIsTime << std::endl; } // Compute origin based on image corner for(unsigned int i=0; iGetSpacing()[i]; m_OutputOrigin[i] += 0.5 * m_OutputSpacing[i]; } // Instance of the transform object to be passed to the resample // filter. By default, identity transform is applied filter->SetTransform(m_Transform); filter->SetSize(m_OutputSize); filter->SetOutputSpacing(m_OutputSpacing); filter->SetOutputOrigin(m_OutputOrigin); filter->SetDefaultPixelValue(m_DefaultPixelValue); #if ITK_VERSION_MAJOR <= 4 filter->SetNumberOfThreads(this->GetNumberOfThreads()); #else filter->SetNumberOfWorkUnits(this->GetNumberOfWorkUnits()); #endif filter->SetOutputDirection(m_OutputDirection); // <-- NEEDED if we want to keep orientation (in case of PermutAxes for example) // Select interpolator switch (m_InterpolationType) { case NearestNeighbor: { typedef itk::NearestNeighborInterpolateImageFunction InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); filter->SetInterpolator(interpolator); break; } case Linear: { typedef itk::LinearInterpolateImageFunction InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); filter->SetInterpolator(interpolator); break; } case BSpline: { typedef itk::BSplineInterpolateImageFunction InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetSplineOrder(m_BSplineOrder); filter->SetInterpolator(interpolator); break; } case B_LUT: { typedef itk::BSplineInterpolateImageFunctionWithLUT InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetSplineOrder(m_BSplineOrder); interpolator->SetLUTSamplingFactor(m_BLUTSamplingFactor); filter->SetInterpolator(interpolator); break; } case WSINC: { typedef itk::WindowedSincInterpolateImageFunction InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); filter->SetInterpolator(interpolator); break; } } // Initial Gaussian blurring if needed // TODO : replace by itk::DiscreteGaussianImageFilter for small sigma typedef itk::RecursiveGaussianImageFilter GaussianFilterType; std::vector gaussianFilters; if (m_GaussianFilteringEnabled) { for(unsigned int i=0; iSetDirection(i); gaussianFilters[i]->SetOrder(GaussianFilterType::ZeroOrder); gaussianFilters[i]->SetNormalizeAcrossScale(false); gaussianFilters[i]->SetSigma(m_GaussianSigma[i]); // in millimeter ! if (gaussianFilters.size() == 1) { // first gaussianFilters[0]->SetInput(input); } else { gaussianFilters[i]->SetInput(gaussianFilters[i-1]->GetOutput()); } } } if (gaussianFilters.size() > 0) { filter->SetInput(gaussianFilters[gaussianFilters.size()-1]->GetOutput()); } else filter->SetInput(input); } else filter->SetInput(input); // Go ! filter->Update(); // Set output this->GraftOutput(filter->GetOutput()); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- template typename InputImageType::Pointer clitk::ResampleImageSpacing(typename InputImageType::Pointer input, typename InputImageType::SpacingType spacing, int interpolationType) { typedef clitk::ResampleImageWithOptionsFilter ResampleFilterType; typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); resampler->SetInput(input); resampler->SetOutputSpacing(spacing); typename ResampleFilterType::InterpolationTypeEnumeration inter=ResampleFilterType::NearestNeighbor; switch(interpolationType) { case 0: inter = ResampleFilterType::NearestNeighbor; break; case 1: inter = ResampleFilterType::Linear; break; case 2: inter = ResampleFilterType::BSpline; break; case 3: inter = ResampleFilterType::B_LUT; break; case 4: inter = ResampleFilterType::WSINC; break; } resampler->SetInterpolationType(inter); resampler->SetGaussianFilteringEnabled(true); resampler->Update(); return resampler->GetOutput(); } //--------------------------------------------------------------------