#include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MIPS_FOUND #include #endif /** * @description Resample an input scalar image given an input transformation. * @author Vincent Garcia * @date 07/06/2011 */ /** * Trasnformation enumeration. */ enum TransformationEnum { IDENTITY_TRANSFORMATION, LINEAR_TRANSFORMATION, DISPLACEMENT_FIELD_TRANSFORMATION, STATIONARY_VELOCITY_FIELD_TRANSFORMATION }; /** * Structure containing parameters. */ struct Param { std::string inputPath; std::string outputPath; std::string geometryPath; rpi::ImageInterpolatorType interpType; std::string transformPath; TransformationEnum transformType; bool verbose; }; /** * Parses the command line arguments and deduces the corresponding Param structure. * @param argc number of arguments * @param argv array containing the arguments * @param param structure of parameters */ void parseParameters(int argc, char** argv, struct Param & param) { // Program description std::string description = "\b\b\bDESCRIPTION\n"; description += "Resample an input scalar image given an input transformation. "; description += "The supported ransformations are identity, linear transformations, displacement "; description += "field transformations, and stationary velocity field transformations. "; description += "The image specified using the \"--geometry\" option is used to set the resample "; description += "image geometry. If the \"--geometry\" option is not used, the geometry of the "; description += "resampled image will be either similar to the input image geometry if the input "; description += "transformation is a linear transformation, or will be similar to the geometry "; description += "of the input field is the input transformation is a displacement field or a "; description += "stationary velocity field. Several image interpolation methods are proposed."; description += "\nAuthors : Vincent Garcia"; // Option description std::string dInput = "Path to the input image."; std::string dOutput = "Path to the output resampled image."; std::string dGeom = "Path to the image containing to output image geometry."; std::string dIT = "If activated, this options implies to use the identity transformation (i.e. no transformation)."; std::string dLT = "Path to the input linear transformation."; std::string dDFT = "Path to the input displacement field transformation."; std::string dSVFT = "Path to the input stationary velocity field transformation."; std::string dInterp = "Interpolation mode : 0 = nearest neighbor, 1 = linear, 2 = b-spline, and 3 = sinus cardinal (default 1)."; std::string dVerbose = "Verbose mode."; try { // Define command line parser TCLAP::CmdLine cmd( description, ' ', "1.0", true); // Set options TCLAP::SwitchArg aVerbose( "", "verbose", dVerbose, cmd, true); TCLAP::ValueArg aInterp( "", "interpolation", dInterp, false, 1, "uint", cmd ); TCLAP::ValueArg aGeom( "g", "geometry", dGeom, false, "", "string", cmd ); TCLAP::ValueArg aOutput( "o", "output", dOutput, true, "", "string", cmd ); TCLAP::ValueArg aInput( "i", "input", dInput, true, "", "string", cmd ); TCLAP::SwitchArg aIT( "", "identity-transform", dIT, false); TCLAP::ValueArg aLT( "l", "linear-transform", dLT, false, "", "string" ); TCLAP::ValueArg aDFT( "d", "displacement-field", dDFT, false, "", "string" ); TCLAP::ValueArg aSVFT( "s", "velocity-field", dSVFT, false, "", "string" ); std::vector< TCLAP::Arg* > xorlist; xorlist.push_back(&aIT); xorlist.push_back(&aLT); xorlist.push_back(&aDFT); xorlist.push_back(&aSVFT); cmd.xorAdd(xorlist); // Parse command line cmd.parse( argc, argv ); // Set parameters param.inputPath = aInput.getValue(); param.outputPath = aOutput.getValue(); param.geometryPath = aGeom.getValue(); param.verbose = aVerbose.getValue(); // Set transformation parameter if (aIT.getValue()) { param.transformType = IDENTITY_TRANSFORMATION; param.transformPath = ""; } if (aLT.getValue().compare("")!=0) { param.transformType = LINEAR_TRANSFORMATION; param.transformPath = aLT.getValue(); } else if (aDFT.getValue().compare("")!=0) { param.transformType = DISPLACEMENT_FIELD_TRANSFORMATION; param.transformPath = aDFT.getValue(); } else if (aSVFT.getValue().compare("")!=0) { param.transformType = STATIONARY_VELOCITY_FIELD_TRANSFORMATION; param.transformPath = aSVFT.getValue(); } // Set interpolation parameter unsigned int interp = aInterp.getValue(); if (interp==0) param.interpType = rpi::INTERPOLATOR_NEAREST_NEIGHBOR; else if (interp==1) param.interpType = rpi::INTERPOLATOR_LINEAR; else if (interp==2) param.interpType = rpi::INTERPOLATOR_BSLPINE; else if (interp==3) param.interpType = rpi::INTERPOLATOR_SINUS_CARDINAL; else throw std::runtime_error("Interpolation mode not recognized."); } catch (TCLAP::ArgException &e) { std::cerr << "Error: " << e.error() << " for argument " << e.argId() << std::endl; throw std::runtime_error("Unable to parse the command line arguments."); } } /** * Prints parameters. * @param param parameters */ void printParameters(struct Param param) { if (!param.verbose) return; std::cout << "Input image : " << param.inputPath << std::endl; std::cout << "Output image : " << param.outputPath << std::endl; if (param.geometryPath.compare("")) std::cout << "Geometry : " << param.geometryPath << std::endl; std::cout << "Transformation : " << param.transformPath << std::endl; std::cout << "Interpolation : "; if (param.interpType == rpi::INTERPOLATOR_NEAREST_NEIGHBOR) std::cout << "nearest neighbor" << std::endl; else if (param.interpType == rpi::INTERPOLATOR_LINEAR) std::cout << "linear" << std::endl; else if (param.interpType == rpi::INTERPOLATOR_BSLPINE) std::cout << "b-spline" << std::endl; else if (param.interpType == rpi::INTERPOLATOR_SINUS_CARDINAL) std::cout << "sinus cardinal" << std::endl; } /** * Reads the input image in the correct format, ressamples it, and save it. * @param param parameters */ template void resample(Param param) { // Type definition typedef itk::Image ImageType; typedef itk::IdentityTransform IdentityTransformType; typedef itk::Transform LinearTransformType; typedef rpi::DisplacementFieldTransform DFTransformType; typedef itk::StationaryVelocityFieldTransform SVFTransformType; typedef typename DFTransformType::VectorFieldType VectorFieldType; try { // Output image geometry typename ImageType::PointType origin; typename ImageType::SpacingType spacing; typename ImageType::SizeType size; typename ImageType::DirectionType direction; // Read image typename ImageType::Pointer input = rpi::readImage( param.inputPath ); // Switch on transformation type switch (param.transformType) { case IDENTITY_TRANSFORMATION : { // Read transformation typename IdentityTransformType::Pointer identity = IdentityTransformType::New(); // Get geometry if (param.geometryPath.compare("")!=0) rpi::getGeometryFromImageHeader(param.geometryPath, origin, spacing, size, direction); else rpi::getGeometryFromImage(input, origin, spacing, size, direction); // Resample and write image rpi::resampleAndWriteImage(input, origin, spacing, size, direction, identity, param.outputPath, param.interpType ); } break; case LINEAR_TRANSFORMATION : { // Read transformation typename LinearTransformType::Pointer linear = rpi::readLinearTransformation(param.transformPath); // Get geometry if (param.geometryPath.compare("")!=0) rpi::getGeometryFromImageHeader(param.geometryPath, origin, spacing, size, direction); else rpi::getGeometryFromImage(input, origin, spacing, size, direction); // Resample and write image rpi::resampleAndWriteImage(input, origin, spacing, size, direction, linear, param.outputPath, param.interpType ); } break; case DISPLACEMENT_FIELD_TRANSFORMATION : { // Read transformation typename DFTransformType::Pointer df = rpi::readDisplacementField(param.transformPath); // Get geometry if (param.geometryPath.compare("")!=0) rpi::getGeometryFromImageHeader(param.geometryPath, origin, spacing, size, direction); else rpi::getGeometryFromImage(df->GetParametersAsVectorField(), origin, spacing, size, direction); // Resample and write image rpi::resampleAndWriteImage(input, origin, spacing, size, direction, df, param.outputPath, param.interpType ); } break; case STATIONARY_VELOCITY_FIELD_TRANSFORMATION : { // Read transformation typename SVFTransformType::Pointer svf = rpi::readStationaryVelocityField(param.transformPath); // Get geometry if (param.geometryPath.compare("")!=0) rpi::getGeometryFromImageHeader(param.geometryPath, origin, spacing, size, direction); else rpi::getGeometryFromImage(svf->GetParametersAsVectorField(), origin, spacing, size, direction); // Create a displacement field from the stationary velocity field typename DFTransformType::Pointer df = DFTransformType::New(); df->SetParametersAsVectorField( svf->GetDisplacementFieldAsVectorField() ); // Resample and write image rpi::resampleAndWriteImage(input, origin, spacing, size, direction, df, param.outputPath, param.interpType ); } break; default : { throw std::runtime_error("Transformation type not supported."); } } } catch( itk::ExceptionObject& e ) { std::cerr << e << std::endl; throw std::runtime_error("Image resampling fail."); } } /** * Main function. */ int main(int argc, char** argv) { #ifdef MIPS_FOUND // Allow to read and write Inrimage itk::InrimageImageIOFactory::RegisterOneFactory(); #endif // Parameters struct Param param; try { // Parse command line options parseParameters( argc, argv, param ); printParameters( param ); // Read ImageIO itk::ImageIOBase::Pointer imageIO = rpi::readImageInformation(param.inputPath); unsigned int dim = imageIO->GetNumberOfDimensions(); itk::IOPixelEnum pixel_type = imageIO->GetPixelType(); itk::IOComponentEnum component_type = imageIO->GetComponentType(); // Switch on pixel type if ( pixel_type== itk::IOPixelEnum::SCALAR) { // Switch on pixel type and dimension if ( dim==3 ) { if ( component_type == itk::IOComponentEnum::UCHAR ) resample(param); else if ( component_type == itk::IOComponentEnum::CHAR ) resample(param); else if ( component_type == itk::IOComponentEnum::USHORT ) resample(param); else if ( component_type == itk::IOComponentEnum::SHORT ) resample(param); else if ( component_type == itk::IOComponentEnum::UINT ) resample(param); else if ( component_type == itk::IOComponentEnum::INT ) resample(param); else if ( component_type == itk::IOComponentEnum::ULONG ) resample(param); else if ( component_type == itk::IOComponentEnum::LONG ) resample(param); else if ( component_type == itk::IOComponentEnum::FLOAT ) resample(param); else if ( component_type == itk::IOComponentEnum::DOUBLE ) resample(param); else throw std::runtime_error( "Component type not supported supported." ); } else throw std::runtime_error( "Dimension not supported yet." ); } else throw std::runtime_error( "Pixel type not supported. Only scalar images are supported yet." ); } catch( std::exception& e ) { std::cerr << std::endl << "Error: " << e.what() << std::endl; return EXIT_FAILURE; }; return EXIT_SUCCESS; }