-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP: ENH: Executable linked to elastix.lib, subset of elastix.exe fun…
…ctions
- Loading branch information
Showing
2 changed files
with
382 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |