X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=tools%2FclitkAffineTransformGenericFilter.txx;h=ab488f3710edcddb8952f142a53d051acf157827;hb=f2abd66846f46f61e6f16e339da46515525826b1;hp=d3cd19e265a84b411ffd27a0791672502ca1d0d2;hpb=dc2e20ab3204d5782db1c0750a7a4b5882d3db89;p=clitk.git diff --git a/tools/clitkAffineTransformGenericFilter.txx b/tools/clitkAffineTransformGenericFilter.txx index d3cd19e..ab488f3 100644 --- a/tools/clitkAffineTransformGenericFilter.txx +++ b/tools/clitkAffineTransformGenericFilter.txx @@ -22,6 +22,9 @@ #include #include #include +#include +#include "clitkElastix.h" +#include "clitkResampleImageWithOptionsFilter.h" namespace clitk { @@ -106,6 +109,95 @@ namespace clitk } //------------------------------------------------------------------- + + + //------------------------------------------------------------------- + // Compute updated bounding box + //------------------------------------------------------------------- + template + vnl_vector + AffineTransformGenericFilter::ComputeSize(vnl_vector inputSize, vnl_matrix transformationMatrix, bool returnMin) + { + //Compute input corners + int Dimension = inputSize.size(); + vnl_matrix vnlOutputSize(std::pow(2, Dimension), Dimension); + vnlOutputSize.fill(0); + if (Dimension == 2) { + for(unsigned int i=0; i< Dimension; i++) + vnlOutputSize[3][i] = inputSize[i]; + vnlOutputSize[1][0] = inputSize[0]; + vnlOutputSize[2][1] = inputSize[1]; + } else if (Dimension == 3) { + for(unsigned int i=0; i< Dimension; i++) + vnlOutputSize[7][i] = inputSize[i]; + vnlOutputSize[1][0] = inputSize[0]; + vnlOutputSize[2][1] = inputSize[1]; + vnlOutputSize[3][2] = inputSize[2]; + vnlOutputSize[4][0] = inputSize[0]; + vnlOutputSize[4][1] = inputSize[1]; + vnlOutputSize[5][1] = inputSize[1]; + vnlOutputSize[5][2] = inputSize[2]; + vnlOutputSize[6][0] = inputSize[0]; + vnlOutputSize[6][2] = inputSize[2]; + } else { //Dimension ==4 + for(unsigned int i=0; i< Dimension; i++) + vnlOutputSize[15][i] = inputSize[i]; + vnlOutputSize[1][0] = inputSize[0]; + vnlOutputSize[2][1] = inputSize[1]; + vnlOutputSize[3][2] = inputSize[2]; + vnlOutputSize[4][3] = inputSize[3]; + vnlOutputSize[5][0] = inputSize[0]; + vnlOutputSize[5][1] = inputSize[1]; + vnlOutputSize[6][0] = inputSize[0]; + vnlOutputSize[6][2] = inputSize[2]; + vnlOutputSize[7][0] = inputSize[0]; + vnlOutputSize[7][3] = inputSize[3]; + vnlOutputSize[8][1] = inputSize[1]; + vnlOutputSize[8][2] = inputSize[2]; + vnlOutputSize[9][1] = inputSize[1]; + vnlOutputSize[9][3] = inputSize[3]; + vnlOutputSize[10][2] = inputSize[2]; + vnlOutputSize[10][3] = inputSize[3]; + vnlOutputSize[11][0] = inputSize[0]; + vnlOutputSize[11][1] = inputSize[1]; + vnlOutputSize[11][2] = inputSize[2]; + vnlOutputSize[12][0] = inputSize[0]; + vnlOutputSize[12][1] = inputSize[1]; + vnlOutputSize[12][3] = inputSize[3]; + vnlOutputSize[13][0] = inputSize[0]; + vnlOutputSize[13][2] = inputSize[2]; + vnlOutputSize[13][3] = inputSize[3]; + vnlOutputSize[14][1] = inputSize[1]; + vnlOutputSize[14][2] = inputSize[2]; + vnlOutputSize[14][3] = inputSize[3]; + } + + //Compute the transformation of all corner + for (unsigned int i=0; i< std::pow(2, Dimension); ++i) + vnlOutputSize.set_row(i, transformationMatrix*vnlOutputSize.get_row(i)); + + //Compute the bounding box taking the max and the min + vnl_vector minBB(vnlOutputSize.get_row(0)), maxBB(vnlOutputSize.get_row(0)); + for (unsigned int i=0; i< std::pow(2, Dimension); ++i) { + for (unsigned int j=0; j< Dimension; ++j) { + if (vnlOutputSize[i][j] < minBB[j]) + minBB[j] = vnlOutputSize[i][j]; + if (vnlOutputSize[i][j] > maxBB[j]) + maxBB[j] = vnlOutputSize[i][j]; + } + } + + //Compute the size + if (returnMin) + return minBB; + else { + vnl_vector size; + size = maxBB - minBB; + + return size; + } + } + //------------------------------------------------------------------- //------------------------------------------------------------------- @@ -128,6 +220,173 @@ namespace clitk reader->Update(); typename InputImageType::Pointer input= reader->GetOutput(); + //Adaptative size, spacing origin (use previous clitkResampleImage) + if (m_ArgsInfo.adaptive_given) { + // Filter + typedef clitk::ResampleImageWithOptionsFilter ResampleImageFilterType; + typename ResampleImageFilterType::Pointer filter = ResampleImageFilterType::New(); + filter->SetInput(input); + + // Set Verbose + filter->SetVerboseOptions(m_ArgsInfo.verbose_flag); + + // Set size / spacing + static const unsigned int dim = OutputImageType::ImageDimension; + typename OutputImageType::SpacingType spacing; + typename OutputImageType::SizeType size; + typename OutputImageType::PointType origin; + typename OutputImageType::DirectionType direction; + + if (m_ArgsInfo.like_given) { + itk::ImageIOBase::Pointer header = clitk::readImageHeader(m_ArgsInfo.like_arg); + if (header) { + for(unsigned int i=0; iGetSpacing(i); + size[i] = header->GetDimensions(i); + origin[i] = header->GetOrigin(i); + } + for(unsigned int i=0; iGetDirection(i)[j]; + } + } + filter->SetOutputSpacing(spacing); + filter->SetOutputSize(size); + filter->SetOutputOrigin(origin); + filter->SetOutputDirection(direction); + } + else { + std::cerr << "*** Warning : I could not read '" << m_ArgsInfo.like_arg << "' ***" << std::endl; + exit(0); + } + } + else { + if (m_ArgsInfo.spacing_given == 1) { + filter->SetOutputIsoSpacing(m_ArgsInfo.spacing_arg[0]); + } + else if ((m_ArgsInfo.spacing_given != 0) && (m_ArgsInfo.size_given != 0)) { + std::cerr << "Error: use spacing or size, not both." << std::endl; + exit(0); + } + else if (m_ArgsInfo.spacing_given) { + if ((m_ArgsInfo.spacing_given != 0) && (m_ArgsInfo.spacing_given != dim)) { + std::cerr << "Error: spacing should have one or " << dim << " values." << std::endl; + exit(0); + } + for(unsigned int i=0; iSetOutputSpacing(spacing); + } + else if (m_ArgsInfo.size_given) { + if ((m_ArgsInfo.size_given != 0) && (m_ArgsInfo.size_given != dim)) { + std::cerr << "Error: size should have " << dim << " values." << std::endl; + exit(0); + } + for(unsigned int i=0; iSetOutputSize(size); + } + for(unsigned int i=0; iGetOrigin()[i]; + } + for(unsigned int i=0; iGetDirection()[i][j]; + } + } + filter->SetOutputOrigin(origin); + filter->SetOutputDirection(direction); + } + + // Set temporal dimension + //filter->SetLastDimensionIsTime(m_ArgsInfo.time_flag); + + // Set Gauss + filter->SetGaussianFilteringEnabled(m_ArgsInfo.autogauss_flag); + if (m_ArgsInfo.gauss_given != 0) { + typename ResampleImageFilterType::GaussianSigmaType g; + for(unsigned int i=0; iSetGaussianSigma(g); + } + + // Set Interpolation + int interp = m_ArgsInfo.interp_arg; + if (interp == 0) { + filter->SetInterpolationType(ResampleImageFilterType::NearestNeighbor); + } else { + if (interp == 1) { + filter->SetInterpolationType(ResampleImageFilterType::Linear); + } else { + if (interp == 2) { + filter->SetInterpolationType(ResampleImageFilterType::BSpline); + } else { + if (interp == 3) { + filter->SetInterpolationType(ResampleImageFilterType::B_LUT); + } else { + std::cerr << "Error. I do not know interpolation '" << m_ArgsInfo.interp_arg + << "'. Choose among: nn, linear, bspline, blut, windowed sinc" << std::endl; + exit(0); + } + } + } + } + + // Set default pixel value + filter->SetDefaultPixelValue(m_ArgsInfo.pad_arg); + + // Set thread + //if (m_ArgsInfo.thread_given) { + // filter->SetNumberOfThreads(m_ArgsInfo.thread_arg); + //} + + // Go ! + filter->Update(); + typename OutputImageType::Pointer output = filter->GetOutput(); + //this->template SetNextOutput(outputImage); + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + return; + } + + //Gaussian pre-filtering + typename itk::Vector gaussianSigma; + gaussianSigma.Fill(0); + bool gaussianFilteringEnabled(false); + bool autoGaussEnabled(false); + if (m_ArgsInfo.autogauss_given) { // Gaussian filter auto + autoGaussEnabled = m_ArgsInfo.autogauss_flag; + } + if (m_ArgsInfo.gauss_given) { // Gaussian filter set by user + gaussianFilteringEnabled = true; + if (m_ArgsInfo.gauss_given == 1) + { + for (unsigned int i=0; i ResampleFilterType; typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); @@ -138,7 +397,7 @@ namespace clitk { if (m_ArgsInfo.matrix_given) { - std::cerr << "You must use either rotate/translate or matrix options" << std::cout; + std::cerr << "You must use either rotate/translate or matrix options" << std::endl; return; } itk::Array transformParameters(2 * Dimension); @@ -181,9 +440,8 @@ namespace clitk } else { if (m_ArgsInfo.elastix_given) { - std::vector s; - for(uint i=0; i(s); + std::string filename(m_ArgsInfo.elastix_arg); + matrix = createMatrixFromElastixFile(filename, m_Verbose); } else matrix.SetIdentity(); @@ -212,6 +470,15 @@ namespace clitk likeReader->SetFileName(m_ArgsInfo.like_arg); likeReader->Update(); resampler->SetOutputParametersFromImage(likeReader->GetOutput()); + resampler->SetOutputDirection(likeReader->GetOutput()->GetDirection()); + if (autoGaussEnabled) { // Automated sigma when downsample + for(unsigned int i=0; iGetOutput()->GetSpacing()[i] > input->GetSpacing()[i]) { // downsample + gaussianSigma[i] = 0.5*likeReader->GetOutput()->GetSpacing()[i];// / inputSpacing[i]); + } + else gaussianSigma[i] = 0; // will be ignore after + } + } } else if(m_ArgsInfo.transform_grid_flag) { typename itk::Matrix invMatrix( matrix.GetInverse() ); typename itk::Matrix invRotMatrix( clitk::GetRotationalPartMatrix(invMatrix) ); @@ -223,12 +490,6 @@ namespace clitk if (m_ArgsInfo.origin_given) std::cout << "Warning --origin ignored (because --transform_grid_flag)" << std::endl; - // Spacing is influenced by affine transform matrix and input direction - typename InputImageType::SpacingType outputSpacing; - outputSpacing = invRotMatrix * - input->GetDirection() * - input->GetSpacing(); - // Origin is influenced by translation but not by input direction typename InputImageType::PointType outputOrigin; outputOrigin = invRotMatrix * @@ -237,13 +498,30 @@ namespace clitk // Size is influenced by affine transform matrix and input direction // Size is converted to double, transformed and converted back to size type. - vnl_vector vnlOutputSize(Dimension); + // Determine the bounding box tranforming all corners + vnl_vector vnlOutputSize(Dimension), vnlOutputmmSize(Dimension), vnlOutputOffset(Dimension); + typename InputImageType::SpacingType outputSpacing; for(unsigned int i=0; i< Dimension; i++) { vnlOutputSize[i] = input->GetLargestPossibleRegion().GetSize()[i]; + vnlOutputmmSize[i] = input->GetLargestPossibleRegion().GetSize()[i]*input->GetSpacing()[i]; + vnlOutputOffset[i] = input->GetLargestPossibleRegion().GetSize()[i]*input->GetSpacing()[i]; + } + vnlOutputSize = ComputeSize(vnlOutputSize, invRotMatrix.GetVnlMatrix() * input->GetDirection().GetVnlMatrix(), 0); + vnlOutputmmSize = ComputeSize(vnlOutputmmSize, invRotMatrix.GetVnlMatrix() * input->GetDirection().GetVnlMatrix(), 0); + vnlOutputOffset = ComputeSize(vnlOutputOffset, invRotMatrix.GetVnlMatrix() * input->GetDirection().GetVnlMatrix(), 1); + for(unsigned int i=0; i< Dimension; i++) { + outputSpacing[i] = vnlOutputmmSize[i]/lrint(vnlOutputSize[i]); + outputOrigin[i] += vnlOutputOffset[i]; } - vnlOutputSize = invRotMatrix * - input->GetDirection().GetVnlMatrix() * - vnlOutputSize; + if (autoGaussEnabled) { // Automated sigma when downsample + for(unsigned int i=0; i input->GetSpacing()[i]) { // downsample + gaussianSigma[i] = 0.5*outputSpacing[i];// / inputSpacing[i]); + } + else gaussianSigma[i] = 0; // will be ignore after + } + } + typename OutputImageType::SizeType outputSize; for(unsigned int i=0; i< Dimension; i++) { // If the size is negative, we have a flip and we must modify @@ -272,6 +550,14 @@ namespace clitk for(unsigned int i=0; i< Dimension; i++) outputSpacing[i]=m_ArgsInfo.spacing_arg[i]; } else outputSpacing=input->GetSpacing(); + if (autoGaussEnabled) { // Automated sigma when downsample + for(unsigned int i=0; i input->GetSpacing()[i]) { // downsample + gaussianSigma[i] = 0.5*outputSpacing[i];// / inputSpacing[i]); + } + else gaussianSigma[i] = 0; // will be ignore after + } + } //Origin typename OutputImageType::PointType outputOrigin; @@ -280,10 +566,19 @@ namespace clitk outputOrigin[i]=m_ArgsInfo.origin_arg[i]; } else outputOrigin=input->GetOrigin(); + //Direction + typename OutputImageType::DirectionType outputDirection; + if (m_ArgsInfo.direction_given) { + for(unsigned int j=0; j< Dimension; j++) + for(unsigned int i=0; i< Dimension; i++) + outputDirection[j][i]=m_ArgsInfo.direction_arg[i+Dimension*j]; + } else outputDirection=input->GetDirection(); + // Set resampler->SetSize( outputSize ); resampler->SetOutputSpacing( outputSpacing ); resampler->SetOutputOrigin( outputOrigin ); + resampler->SetOutputDirection( outputDirection ); } @@ -314,9 +609,31 @@ namespace clitk std::cout << "Setting the output size to " << resampler->GetSize() << "..." << std::endl; std::cout << "Setting the output spacing to " << resampler->GetOutputSpacing() << "..." << std::endl; std::cout << "Setting the output origin to " << resampler->GetOutputOrigin() << "..." << std::endl; + std::cout << "Setting the output direction to " << resampler->GetOutputDirection() << "..." << std::endl; } - resampler->SetInput( input ); + typedef itk::RecursiveGaussianImageFilter GaussianFilterType; + std::vector gaussianFilters; + if (gaussianFilteringEnabled || autoGaussEnabled) { + for(unsigned int i=0; iSetDirection(i); + gaussianFilters[i]->SetOrder(GaussianFilterType::ZeroOrder); + gaussianFilters[i]->SetNormalizeAcrossScale(false); + gaussianFilters[i]->SetSigma(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) { + resampler->SetInput(gaussianFilters[gaussianFilters.size()-1]->GetOutput()); + } else resampler->SetInput(input); + } else resampler->SetInput(input); + resampler->SetTransform( affineTransform ); resampler->SetInterpolator( genericInterpolator->GetInterpolatorPointer()); resampler->SetDefaultPixelValue( static_cast(m_ArgsInfo.pad_arg) ); @@ -358,6 +675,37 @@ namespace clitk reader->Update(); typename InputImageType::Pointer input= reader->GetOutput(); + //Gaussian pre-filtering + typename itk::Vector gaussianSigma; + gaussianSigma.Fill(0); + bool gaussianFilteringEnabled(false); + bool autoGaussEnabled(false); + if (m_ArgsInfo.autogauss_given) { // Gaussian filter auto + autoGaussEnabled = m_ArgsInfo.autogauss_flag; + } + if (m_ArgsInfo.gauss_given) { // Gaussian filter set by user + gaussianFilteringEnabled = true; + if (m_ArgsInfo.gauss_given == 1) + { + for (unsigned int i=0; i ResampleFilterType; typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); @@ -368,7 +716,7 @@ namespace clitk { if (m_ArgsInfo.matrix_given) { - std::cerr << "You must use either rotate/translate or matrix options" << std::cout; + std::cerr << "You must use either rotate/translate or matrix options" << std::endl; return; } itk::Array transformParameters(2 * Dimension); @@ -437,6 +785,15 @@ namespace clitk resampler->SetSize( likeReader->GetOutput()->GetLargestPossibleRegion().GetSize() ); resampler->SetOutputSpacing( likeReader->GetOutput()->GetSpacing() ); resampler->SetOutputOrigin( likeReader->GetOutput()->GetOrigin() ); + resampler->SetOutputDirection( likeReader->GetOutput()->GetDirection() ); + if (autoGaussEnabled) { // Automated sigma when downsample + for(unsigned int i=0; iGetOutput()->GetSpacing()[i] > input->GetSpacing()[i]) { // downsample + gaussianSigma[i] = 0.5*likeReader->GetOutput()->GetSpacing()[i];// / inputSpacing[i]); + } + else gaussianSigma[i] = 0; // will be ignore after + } + } } else { //Size typename OutputImageType::SizeType outputSize; @@ -452,6 +809,14 @@ namespace clitk for(unsigned int i=0; i< Dimension; i++) outputSpacing[i]=m_ArgsInfo.spacing_arg[i]; } else outputSpacing=input->GetSpacing(); + if (autoGaussEnabled) { // Automated sigma when downsample + for(unsigned int i=0; i input->GetSpacing()[i]) { // downsample + gaussianSigma[i] = 0.5*outputSpacing[i];// / inputSpacing[i]); + } + else gaussianSigma[i] = 0; // will be ignore after + } + } std::cout<<"Setting the spacing to "<GetOrigin(); std::cout<<"Setting the origin to "<GetDirection(); + std::cout<<"Setting the direction to "<SetSize( outputSize ); resampler->SetOutputSpacing( outputSpacing ); resampler->SetOutputOrigin( outputOrigin ); + resampler->SetOutputDirection( outputDirection ); } + typedef itk::RecursiveGaussianImageFilter GaussianFilterType; + std::vector gaussianFilters; + if (gaussianFilteringEnabled || autoGaussEnabled) { + for(unsigned int i=0; iSetDirection(i); + gaussianFilters[i]->SetOrder(GaussianFilterType::ZeroOrder); + gaussianFilters[i]->SetNormalizeAcrossScale(false); + gaussianFilters[i]->SetSigma(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) { + resampler->SetInput(gaussianFilters[gaussianFilters.size()-1]->GetOutput()); + } else resampler->SetInput(input); + } else resampler->SetInput(input); + resampler->SetInput( input ); resampler->SetTransform( affineTransform ); resampler->SetInterpolator( genericInterpolator->GetInterpolatorPointer()); @@ -491,140 +888,6 @@ namespace clitk } //------------------------------------------------------------------- - - - //------------------------------------------------------------------- - template - template - typename itk::Matrix - AffineTransformGenericFilter::createMatrixFromElastixFile(std::vector & filename) - { - if (Dimension != 3) { - FATAL("Only 3D yet" << std::endl); - } - typename itk::Matrix matrix; - - itk::CenteredEuler3DTransform::Pointer mat = itk::CenteredEuler3DTransform::New(); - itk::CenteredEuler3DTransform::Pointer previous; - for(uint j=0; j cor; - GetValuesFromValue(s, cor); - - // Get Transformparameters - GetElastixValueFromTag(is, "TransformParameters ", s); // space is needed - if (!b) { - FATAL("Error must read 'TransformParameters' in " << filename[j] << std::endl); - } - std::vector results; - GetValuesFromValue(s, results); - - // construct a stream from the string - itk::CenteredEuler3DTransform::ParametersType p; - p.SetSize(9); - for(uint i=0; i<3; i++) - p[i] = atof(results[i].c_str()); // Rotation - for(uint i=0; i<3; i++) - p[i+3] = atof(cor[i].c_str()); // Centre of rotation - for(uint i=0; i<3; i++) - p[i+6] = atof(results[i+3].c_str()); // Translation - mat->SetParameters(p); - - if (m_Verbose) { - std::cout << "Rotation (deg) : " << rad2deg(p[0]) << " " << rad2deg(p[1]) << " " << rad2deg(p[2]) << std::endl; - std::cout << "Center of rot (phy) : " << p[3] << " " << p[4] << " " << p[5] << std::endl; - std::cout << "Translation (phy) : " << p[6] << " " << p[7] << " " << p[8] << std::endl; - } - - // Compose with previous if needed - if (j!=0) { - mat->Compose(previous); - if (m_Verbose) { - std::cout << "Composed rotation (deg) : " << rad2deg(mat->GetAngleX()) << " " << rad2deg(mat->GetAngleY()) << " " << rad2deg(mat->GetAngleZ()) << std::endl; - std::cout << "Composed center of rot (phy) : " << mat->GetCenter() << std::endl; - std::cout << "Compsoed translation (phy) : " << mat->GetTranslation() << std::endl; - } - } - // previous = mat->Clone(); // ITK4 - previous = itk::CenteredEuler3DTransform::New(); - previous->SetParameters(mat->GetParameters()); - } - - mat = previous; - for(uint i=0; i<3; i++) - for(uint j=0; j<3; j++) - matrix[i][j] = mat->GetMatrix()[i][j]; - // Offset is -Rc + t + c - matrix[0][3] = mat->GetOffset()[0]; - matrix[1][3] = mat->GetOffset()[1]; - matrix[2][3] = mat->GetOffset()[2]; - matrix[3][3] = 1; - - return matrix; - } - - //------------------------------------------------------------------- - template - bool - AffineTransformGenericFilter::GetElastixValueFromTag(std::ifstream & is, - std::string tag, - std::string & value) - { - std::string line; - is.seekg (0, is.beg); - while(std::getline(is, line)) { - unsigned pos = line.find(tag); - if (pos - void - AffineTransformGenericFilter::GetValuesFromValue(const std::string & s, - std::vector & values) - { - std::stringstream strstr(s); - std::istream_iterator it(strstr); - std::istream_iterator end; - std::vector results(it, end); - values.clear(); - values.resize(results.size()); - for(uint i=0; i