1 #include <tclap/CmdLine.h> 4 #include <itkComposeDisplacementFieldsImageFilter.h> 5 #include <itkVectorLinearInterpolateNearestNeighborExtrapolateImageFunction.h> 6 #include <itkMultiplyImageFilter.h> 11 int main(
int argc,
char **argv)
13 std::string descriptionMessage =
"Performs mathematical operations on dense transformations: exponentiation, composition, BCH composition \n";
14 descriptionMessage +=
"This software has known limitations: you might have to use it several times in a row or in combination with regular image arithmetic to perform the operation you want,\n";
15 descriptionMessage +=
"for example taking the power of a log-transform, requires you to multiply the field outside of this tool.\n";
16 descriptionMessage +=
"The logarithm computation of a field is also not yet implemented.\n";
17 descriptionMessage +=
"INRIA / IRISA - VisAGeS/Empenn Team";
19 TCLAP::CmdLine cmd(descriptionMessage,
' ',ANIMA_VERSION);
21 TCLAP::ValueArg<std::string> inArg(
"i",
"input",
"Input transformation (SVF or dense)",
true,
"",
"input transformation",cmd);
22 TCLAP::ValueArg<std::string> composeArg(
"c",
"compose",
"Composed transformation (SVF or dense)",
false,
"",
"composed transformation",cmd);
23 TCLAP::ValueArg<std::string> outArg(
"o",
"output",
"output image",
true,
"",
"output image",cmd);
25 TCLAP::SwitchArg expArg(
"E",
"exp",
"Exponentiate inputs (if not selected, composition will be done using BCH)",cmd,
false);
26 TCLAP::SwitchArg compositionArg(
"R",
"regular-composition",
"Use regular composition (transformations are taken as dense field (if not selected and no exponentiation is done, BCH will be used)",cmd,
false);
28 TCLAP::ValueArg<unsigned int> bchArg(
"b",
"bch-order",
"Order of BCH composition (in between 1 and 4, default: 2)",
false,2,
"BCH order",cmd);
29 TCLAP::ValueArg<unsigned int> expOrderArg(
"e",
"exp-order",
"Order of field exponentiation approximation (in between 0 and 1, default: 0)",
false,0,
"exponentiation order",cmd);
30 TCLAP::ValueArg<unsigned int> dividerArg(
"d",
"div-order",
"If BCH composition of order > 1, divide input fields by d (default: 1)",
false,1,
"BCH field divider",cmd);
32 TCLAP::ValueArg<unsigned int> nbpArg(
"T",
"numberofthreads",
"Number of threads to run on (default : all cores)",
false,itk::MultiThreaderBase::GetGlobalDefaultNumberOfThreads(),
"number of threads",cmd);
38 catch (TCLAP::ArgException& e)
40 std::cerr <<
"Error: " << e.error() <<
"for argument " << e.argId() << std::endl;
44 typedef itk::StationaryVelocityFieldTransform <double,3> SVFTransformType;
45 typedef rpi::DisplacementFieldTransform <double,3> DenseTransformType;
46 typedef SVFTransformType::VectorFieldType FieldType;
48 FieldType::Pointer inputField = anima::readImage <FieldType> (inArg.getValue());
49 FieldType::Pointer composeField = ITK_NULLPTR;
50 if (composeArg.getValue() !=
"")
51 composeField = anima::readImage <FieldType> (composeArg.getValue());
55 std::cout <<
"Taking transformation(s) exponential" << std::endl;
56 SVFTransformType::Pointer tmpTrsf = SVFTransformType::New();
57 DenseTransformType::Pointer outTrsf = DenseTransformType::New();
59 tmpTrsf->SetParametersAsVectorField(inputField);
62 inputField = const_cast <FieldType *> (outTrsf->GetParametersAsVectorField());
66 tmpTrsf->SetParametersAsVectorField(composeField);
69 composeField = const_cast <FieldType *> (outTrsf->GetParametersAsVectorField());
76 std::cout <<
"Composing transformations ";
78 if (expArg.isSet() || compositionArg.isSet())
80 std::cout <<
"using regular transformation composition" << std::endl;
81 typedef itk::ComposeDisplacementFieldsImageFilter <FieldType,FieldType> ComposeFilterType;
82 typedef FieldType::PixelType VectorType;
83 typedef itk::VectorLinearInterpolateNearestNeighborExtrapolateImageFunction <FieldType,VectorType::ValueType> VectorInterpolateFunctionType;
85 ComposeFilterType::Pointer composeFilter = ComposeFilterType::New();
86 composeFilter->SetWarpingField(composeField);
87 composeFilter->SetDisplacementField(inputField);
88 composeFilter->SetNumberOfWorkUnits(nbpArg.getValue());
90 VectorInterpolateFunctionType::Pointer interpolator = VectorInterpolateFunctionType::New();
92 composeFilter->SetInterpolator(interpolator);
93 composeFilter->Update();
95 inputField = composeFilter->GetOutput();
96 inputField->DisconnectPipeline();
100 unsigned int dividerValue = 1;
101 if (bchArg.getValue() > 1)
102 dividerValue = dividerArg.getValue();
104 std::cout <<
"using BCH approximation of order " << bchArg.getValue() <<
", dividing input fields by " << dividerValue << std::endl;
106 if (dividerValue != 1)
108 typedef itk::MultiplyImageFilter <FieldType, itk::Image <double, 3>, FieldType> MultiplyConstantFilterType;
109 MultiplyConstantFilterType::Pointer inputFieldDivider = MultiplyConstantFilterType::New();
110 inputFieldDivider->SetInput(inputField);
111 inputFieldDivider->SetConstant(1.0 / dividerValue);
112 inputFieldDivider->SetNumberOfWorkUnits(nbpArg.getValue());
114 inputFieldDivider->Update();
115 inputField = inputFieldDivider->GetOutput();
116 inputField->DisconnectPipeline();
118 MultiplyConstantFilterType::Pointer composeFieldDivider = MultiplyConstantFilterType::New();
119 composeFieldDivider->SetInput(composeField);
120 composeFieldDivider->SetConstant(1.0 / dividerValue);
121 composeFieldDivider->SetNumberOfWorkUnits(nbpArg.getValue());
123 composeFieldDivider->Update();
124 composeField = composeFieldDivider->GetOutput();
125 composeField->DisconnectPipeline();
128 SVFTransformType::Pointer inputTrsf = SVFTransformType::New();
129 SVFTransformType::Pointer resultTrsf = SVFTransformType::New();
130 SVFTransformType::Pointer composeTrsf = SVFTransformType::New();
132 inputTrsf->SetParametersAsVectorField(inputField);
133 resultTrsf->SetParametersAsVectorField(inputField);
134 composeTrsf->SetParametersAsVectorField(composeField);
136 for (
unsigned int i = 0;i < dividerValue;++i)
138 std::cout <<
"Iteration " << i+1 <<
" / " << dividerValue << std::endl;
139 anima::composeSVF(resultTrsf.GetPointer(),composeTrsf.GetPointer(),nbpArg.getValue(),bchArg.getValue());
141 if (i < dividerValue - 1)
143 anima::composeSVF(inputTrsf.GetPointer(),resultTrsf.GetPointer(),nbpArg.getValue(),bchArg.getValue());
144 resultTrsf->SetParametersAsVectorField(inputTrsf->GetParametersAsVectorField());
145 inputTrsf->SetParametersAsVectorField(inputField);
149 inputField = const_cast <FieldType *> (resultTrsf->GetParametersAsVectorField());
153 anima::writeImage <FieldType> (outArg.getValue(),inputField);
void GetSVFExponential(itk::StationaryVelocityFieldTransform< ScalarType, NDimensions > *baseTrsf, rpi::DisplacementFieldTransform< ScalarType, NDimensions > *resultTransform, unsigned int exponentiationOrder, unsigned int numThreads, bool invert)
void composeSVF(itk::StationaryVelocityFieldTransform< ScalarType, NDimensions > *baseTrsf, itk::StationaryVelocityFieldTransform< ScalarType, NDimensions > *addonTrsf, unsigned int numThreads, unsigned int bchOrder)