Skip to content

Commit

Permalink
WIP: ENH: Executable linked to elastix.lib, subset of elastix.exe fun…
Browse files Browse the repository at this point in the history
…ctions
  • Loading branch information
N-Dekker committed Oct 28, 2021
1 parent 7694040 commit d0ed6b6
Show file tree
Hide file tree
Showing 2 changed files with 382 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ set_target_properties( elastix_lib PROPERTIES OUTPUT_NAME elastix )
target_compile_definitions( elastix_lib PRIVATE ELX_CMAKE_VERSION="${CMAKE_VERSION}" )
target_link_libraries( elastix_lib ${ELASTIX_TARGET_LINK_LIBRARIES} )

add_executable( ElastixLibBasedExe
Main/ElastixLibBasedExe.cxx
)
target_link_libraries( ElastixLibBasedExe elastix_lib )
target_compile_definitions(ElastixLibBasedExe PRIVATE ELX_CMAKE_VERSION="${CMAKE_VERSION}")

#---------------------------------------------------------------------
# Create the transformix executable.

Expand Down
376 changes: 376 additions & 0 deletions Core/Main/ElastixLibBasedExe.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,376 @@
/*=========================================================================
*
* Copyright UMC Utrecht and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/

// Elastix header files:
#include "elastix.h"
#include "elastixlib.h"
#include "elxElastixMain.h"
#include "itkUseMevisDicomTiff.h"

#include <Core/elxVersionMacros.h>

// ITK header files:
#include <itkTimeProbe.h>
#include <itksys/SystemInformation.hxx>
#include <itksys/SystemTools.hxx>

// Standard C++ header files:
#include <cassert>
#include <climits> // For UINT_MAX.
#include <cstddef> // For size_t.
#include <deque>
#include <iostream>
#include <limits>
#include <vector>

namespace
{
using ImageType = itk::Image<float>;

// TODO: Check GenerateImageContainer calls in ElastixMain::Run() for
// more extensive reading.
ImageType::Pointer
ReadImage(const std::string & filename)
{
/** Setup reader. */
const auto imageFileReader = itk::ImageFileReader<ImageType>::New();
imageFileReader->SetFileName(filename);
imageFileReader->Update();
return imageFileReader->GetOutput();
}
} // namespace

int
Main(const int argc, const char * const * const argv)
{

/** Check if "--help" or "--version" was asked for. */
if (argc == 1)
{
std::cout << "Use \"elastix --help\" for information about elastix-usage." << std::endl;
return 0;
}
else if (argc == 2)
{
std::string argument(argv[1]);
if (argument == "-help" || argument == "--help" || argument == "-h")
{
PrintHelp();
return 0;
}
else if (argument == "--version")
{
std::cout << std::fixed;
std::cout << std::showpoint;
std::cout << std::setprecision(3);
std::cout << "elastix version: " << ELASTIX_VERSION_STRING << std::endl;
return 0;
}
else if (argument == "--extended-version")
{
std::cout << std::fixed << std::showpoint << std::setprecision(3) << "elastix version: " << ELASTIX_VERSION_STRING
<< "\nITK version: " << ITK_VERSION_MAJOR << '.' << ITK_VERSION_MINOR << '.' << ITK_VERSION_PATCH
<< "\nBuild date: " << __DATE__ << ' ' << __TIME__
#ifdef _MSC_FULL_VER
<< "\nCompiler: Visual C++ version " << _MSC_FULL_VER << '.' << _MSC_BUILD
#endif
#ifdef __clang__
<< "\nCompiler: Clang"
# ifdef __VERSION__
<< " version " << __VERSION__
# endif
#endif
#if defined(__GNUC__)
<< "\nCompiler: GCC"
# ifdef __VERSION__
<< " version " << __VERSION__
# endif
#endif
<< "\nMemory address size: " << std::numeric_limits<std::size_t>::digits << "-bit"
<< "\nCMake version: " << ELX_CMAKE_VERSION << std::endl;
return 0;
}
else
{
std::cout << "Use \"elastix --help\" for information about elastix-usage." << std::endl;
return 0;
}
}

/** Some typedef's. */
typedef elx::ElastixMain ElastixMainType;
typedef ElastixMainType::ObjectPointer ObjectPointer;
typedef ElastixMainType::DataObjectContainerPointer DataObjectContainerPointer;
typedef ElastixMainType::FlatDirectionCosinesType FlatDirectionCosinesType;

typedef ElastixMainType::ArgumentMapType ArgumentMapType;
typedef ArgumentMapType::value_type ArgumentMapEntryType;

/** Support Mevis Dicom Tiff (if selected in cmake) */
RegisterMevisDicomTiff();

ArgumentMapType argMap;
std::deque<std::string> parameterFileList;
std::string outFolder;

/** Put command line parameters into parameterFileList. */
for (unsigned int i = 1; static_cast<long>(i) < (argc - 1); i += 2)
{
std::string key(argv[i]);
std::string value(argv[i + 1]);

if (key == "-p")
{
/** Queue the ParameterFileNames. */
parameterFileList.push_back(value);
/** The different '-p' are stored in the argMap, with
* keys p(1), p(2), etc. */
std::ostringstream tempPname;
tempPname << "-p(" << parameterFileList.size() << ")";
std::string tempPName = tempPname.str();
argMap.insert(ArgumentMapEntryType(tempPName, value));
}
else
{
if (key == "-out")
{
/** Make sure that last character of the output folder equals a '/' or '\'. */
const char last = value[value.size() - 1];
if (last != '/' && last != '\\')
{
value.append("/");
}
value = itksys::SystemTools::ConvertToOutputPath(value);

/** Note that on Windows, in case the output folder contains a space,
* the path name is double quoted by ConvertToOutputPath, which is undesirable.
* So, we remove these quotes again.
*/
if (itksys::SystemTools::StringStartsWith(value, "\"") && itksys::SystemTools::StringEndsWith(value, "\""))
{
value = value.substr(1, value.length() - 2);
}

/** Save this information. */
outFolder = value;

} // end if key == "-out"

/** Attempt to save the arguments in the ArgumentMap. */
if (argMap.count(key) == 0)
{
argMap.insert(ArgumentMapEntryType(key, value));
}
else
{
/** Duplicate arguments. */
std::cerr << "WARNING!" << std::endl;
std::cerr << "Argument " << key << "is only required once." << std::endl;
std::cerr << "Arguments " << key << " " << value << "are ignored" << std::endl;
}

} // end else (so, if key does not equal "-p")

} // end for loop

/** The argv0 argument, required for finding the component.dll/so's. */
argMap.insert(ArgumentMapEntryType("-argv0", argv[0]));

int returndummy{};

/** Check if at least once the option "-p" is given. */
if (parameterFileList.empty())
{
std::cerr << "ERROR: No CommandLine option \"-p\" given!" << std::endl;
returndummy |= -1;
}

/** Check if the -out option is given. */
if (!outFolder.empty())
{
/** Check if the output directory exists. */
if (!itksys::SystemTools::FileIsDirectory(outFolder))
{
std::cerr << "ERROR: the output directory \"" << outFolder << "\" does not exist." << std::endl;
std::cerr << "You are responsible for creating it." << std::endl;
returndummy |= -2;
}
else
{
/** Setup xout. */
const std::string logFileName = outFolder + "elastix.log";
const int returndummy2{ elx::xoutSetup(logFileName.c_str(), true, true) };
if (returndummy2 != 0)
{
std::cerr << "ERROR while setting up xout." << std::endl;
}
returndummy |= returndummy2;
}
}
else
{
returndummy = -2;
std::cerr << "ERROR: No CommandLine option \"-out\" given!" << std::endl;
}

/** Stop if some fatal errors occurred. */
if (returndummy != 0)
{
return returndummy;
}

elxout << std::endl;

/** Declare a timer, start it and print the start time. */
itk::TimeProbe totaltimer;
totaltimer.Start();
elxout << "elastix is started at " << GetCurrentDateAndTime() << ".\n" << std::endl;

/** Print where elastix was run. */
elxout << "which elastix: " << argv[0] << std::endl;
itksys::SystemInformation info;
info.RunCPUCheck();
info.RunOSCheck();
info.RunMemoryCheck();
elxout << "elastix runs at: " << info.GetHostname() << std::endl;
elxout << " " << info.GetOSName() << " " << info.GetOSRelease() << (info.Is64Bits() ? " (x64), " : ", ")
<< info.GetOSVersion() << std::endl;
elxout << " with " << info.GetTotalPhysicalMemory() << " MB memory, and " << info.GetNumberOfPhysicalCPU()
<< " cores @ " << static_cast<unsigned int>(info.GetProcessorClockFrequency()) << " MHz." << std::endl;


/**
* ********************* START REGISTRATION *********************
*
* Do the (possibly multiple) registration(s).
*/


const int result = [parameterFileList, outFolder, argMap] {
const auto nrOfParameterFiles = parameterFileList.size();

const auto fixedImageFilename = argMap.at("-f");
const auto movingImageFilename = argMap.at("-m");

using elastix::ELASTIX;
ELASTIX elastixObject;
const auto fixedImage = ReadImage(fixedImageFilename);
const auto movingImage = ReadImage(movingImageFilename);

std::vector<ELASTIX::ParameterMapType> parameterMaps(nrOfParameterFiles);

for (std::size_t i{}; i < nrOfParameterFiles; ++i)
{
const auto parameterFileParser = itk::ParameterFileParser::New();
parameterFileParser->SetParameterFileName(parameterFileList[i]);
parameterFileParser->ReadParameterFile();
auto parameterMap = parameterFileParser->GetParameterMap();

parameterMap["FixedImageDimension"] = { std::to_string(fixedImage->GetImageDimension()) };
parameterMap["MovingImageDimension"] = { std::to_string(movingImage->GetImageDimension()) };
parameterMaps[i] = parameterMap;
}

const bool performLogging{ true };
const bool performCout{ true };
ELASTIX::ImagePointer fixedMask{};
ELASTIX::ImagePointer movingMask{};

return elastixObject.RegisterImages(
fixedImage, movingImage, parameterMaps, outFolder, performLogging, performCout, fixedMask, movingMask);
}();


elxout << "-------------------------------------------------------------------------"
<< "\n"
<< std::endl;

/** Stop totaltimer and print it. */
totaltimer.Stop();
elxout << "Total time elapsed: " << ConvertSecondsToDHMS(totaltimer.GetMean(), 1) << ".\n" << std::endl;

/** Exit and return the error code. */
return result;

} // end Main


int
main(int argc, char ** argv)
{
try
{
return Main(argc, argv);
}
catch (const std::exception & stdException)
{
std::cerr << "An error occurred! Exception: " << stdException.what() << '\n';
return EXIT_FAILURE;
}
}

/**
* *********************** PrintHelp ****************************
*/

void
PrintHelp(void)
{
/** Print the version. */
std::cout << std::fixed;
std::cout << std::showpoint;
std::cout << std::setprecision(3);
std::cout << "elastix version: " << ELASTIX_VERSION_STRING << "\n" << std::endl;

/** What is elastix? */
std::cout << "elastix registers a moving image to a fixed image.\n";
std::cout << "The registration-process is specified in the parameter file.\n";
std::cout << " --help, -h displays this message and exit\n";
std::cout << " --version output version information and exit\n"
<< " --extended-version output extended version information and exit\n"
<< std::endl;

/** Mandatory arguments.*/
std::cout << "Call elastix from the command line with mandatory arguments:\n";
std::cout << " -f fixed image\n";
std::cout << " -m moving image\n";
std::cout << " -out output directory\n";
std::cout << " -p parameter file, elastix handles 1 or more \"-p\"\n" << std::endl;

/** Optional arguments.*/
std::cout << "Optional extra commands:\n";
std::cout << " -fMask mask for fixed image\n";
std::cout << " -mMask mask for moving image\n";
std::cout << " -t0 parameter file for initial transform\n";
std::cout << " -priority set the process priority to high, abovenormal, normal (default),\n"
<< " belownormal, or idle (Windows only option)\n";
std::cout << " -threads set the maximum number of threads of elastix\n" << std::endl;

/** The parameter file.*/
std::cout << "The parameter-file must contain all the information "
"necessary for elastix to run properly. That includes which metric to "
"use, which optimizer, which transform, etc. It must also contain "
"information specific for the metric, optimizer, transform, etc. "
"For a usable parameter-file, see the website.\n"
<< std::endl;

std::cout << "Need further help?\nCheck the website http://elastix.isi.uu.nl, "
"or mail [email protected]."
<< std::endl;

} // end PrintHelp()

0 comments on commit d0ed6b6

Please sign in to comment.