From c4ef707bb9433e687d45a06408393413f2abe64a Mon Sep 17 00:00:00 2001 From: Niels Dekker Date: Fri, 24 Feb 2023 22:25:57 +0100 Subject: [PATCH] ENH: Add `ElastixLogLevel` to the ITK interface Added `GetLogLevel` and `SetLogLevel` member functions to both `itk::ElastixRegistrationMethod` and `itk::TransformixFilter`, allowing the user to reduce the amount of logging from elastix and transformix, both to the log file and the console (standard output). --- Core/Kernel/elxlog.h | 4 +- .../itkElastixRegistrationMethodGTest.cxx | 32 +++++++++++ Core/Main/itkElastixLogLevel.h | 53 +++++++++++++++++++ Core/Main/itkElastixRegistrationMethod.h | 6 +++ Core/Main/itkElastixRegistrationMethod.hxx | 5 +- Core/Main/itkTransformixFilter.h | 6 +++ Core/Main/itkTransformixFilter.hxx | 5 +- 7 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 Core/Main/itkElastixLogLevel.h diff --git a/Core/Kernel/elxlog.h b/Core/Kernel/elxlog.h index 0cb75eb00..3ec574532 100644 --- a/Core/Kernel/elxlog.h +++ b/Core/Kernel/elxlog.h @@ -30,7 +30,7 @@ namespace elastix class log { public: - enum class level + enum class level : uint8_t { info, warn, @@ -56,7 +56,7 @@ class log guard(const std::string & log_filename, const bool do_log_to_file, const bool do_log_to_stdout, - const level log_level = {}); + const level log_level); /** Does reset the logging system. */ ~guard(); diff --git a/Core/Main/GTesting/itkElastixRegistrationMethodGTest.cxx b/Core/Main/GTesting/itkElastixRegistrationMethodGTest.cxx index 97cf63028..49acc84e6 100644 --- a/Core/Main/GTesting/itkElastixRegistrationMethodGTest.cxx +++ b/Core/Main/GTesting/itkElastixRegistrationMethodGTest.cxx @@ -144,6 +144,38 @@ Test_WriteBSplineTransformToItkFileFormat(const std::string & rootOutputDirector } // namespace +static_assert(sizeof(itk::ElastixLogLevel) == sizeof(elx::log::level), + "The log level enum types should have the same size!"); + +static_assert(sizeof(itk::ElastixLogLevel) == 1, "The log level enum type should have just one byte!"); + +static_assert(itk::ElastixLogLevel::Info == itk::ElastixLogLevel{}, "The default log level should be `Info`!"); + +static_assert(static_cast(itk::ElastixLogLevel::Info) == static_cast(elx::log::level::info) && + static_cast(itk::ElastixLogLevel::Warning) == static_cast(elx::log::level::warn) && + static_cast(itk::ElastixLogLevel::Error) == static_cast(elx::log::level::err) && + static_cast(itk::ElastixLogLevel::Off) == static_cast(elx::log::level::off), + "Corresponding log level enumerators should have the same underlying integer value!"); + + +GTEST_TEST(itkElastixRegistrationMethod, LogLevel) +{ + using ImageType = itk::Image; + elx::DefaultConstruct> elastixRegistrationMethod; + + ASSERT_EQ(elastixRegistrationMethod.GetLogLevel(), itk::ElastixLogLevel{}); + + for (const auto logLevel : { itk::ElastixLogLevel::Info, + itk::ElastixLogLevel::Warning, + itk::ElastixLogLevel::Error, + itk::ElastixLogLevel::Off }) + { + elastixRegistrationMethod.SetLogLevel(logLevel); + EXPECT_EQ(elastixRegistrationMethod.GetLogLevel(), logLevel); + } +} + + GTEST_TEST(itkElastixRegistrationMethod, IsDefaultInitialized) { constexpr auto ImageDimension = 2U; diff --git a/Core/Main/itkElastixLogLevel.h b/Core/Main/itkElastixLogLevel.h new file mode 100644 index 000000000..8a40c0e5e --- /dev/null +++ b/Core/Main/itkElastixLogLevel.h @@ -0,0 +1,53 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * 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. + * + *=========================================================================*/ +/*========================================================================= + * + * 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. + * + *=========================================================================*/ +#ifndef itkElastixLogLevel_h +#define itkElastixLogLevel_h + +#include "itkIntTypes.h" + +namespace itk +{ +/** The level of logging from elastix and/or transformix */ +enum ElastixLogLevel : uint8_t +{ + Info, //!< Log all messages, even the ones that are only informative. + Warning, //!< Log the error messages, as well as the warnings. + Error, //!< Log only the error messages. + Off //!< Do not log any messages. +}; + +} // namespace itk + +#endif diff --git a/Core/Main/itkElastixRegistrationMethod.h b/Core/Main/itkElastixRegistrationMethod.h index 037b32a5d..e9e495ae0 100644 --- a/Core/Main/itkElastixRegistrationMethod.h +++ b/Core/Main/itkElastixRegistrationMethod.h @@ -36,6 +36,7 @@ #define itkElastixRegistrationMethod_h #include "itkImageSource.h" +#include "itkElastixLogLevel.h" #include "elxElastixMain.h" #include "elxElastixTemplate.h" @@ -252,6 +253,9 @@ class ITK_TEMPLATE_EXPORT ElastixRegistrationMethod : public itk::ImageSource::GenerateData() } // Setup logging. - const elx::log::guard logGuard(logFileName, m_EnableOutput && m_LogToFile, m_EnableOutput && m_LogToConsole); + const elx::log::guard logGuard(logFileName, + m_EnableOutput && m_LogToFile, + m_EnableOutput && m_LogToConsole, + static_cast(m_LogLevel)); // Run the (possibly multiple) registration(s) for (unsigned int i = 0; i < parameterMapVector.size(); ++i) diff --git a/Core/Main/itkTransformixFilter.h b/Core/Main/itkTransformixFilter.h index c6b8211c6..9d02d39db 100644 --- a/Core/Main/itkTransformixFilter.h +++ b/Core/Main/itkTransformixFilter.h @@ -35,6 +35,7 @@ #ifndef itkTransformixFilter_h #define itkTransformixFilter_h +#include "itkElastixLogLevel.h" #include "itkImageSource.h" #include "itkMesh.h" #include "itkTransformBase.h" @@ -212,6 +213,9 @@ class ITK_TEMPLATE_EXPORT TransformixFilter : public ImageSource m_EnableOutput = false; } + itkSetMacro(LogLevel, ElastixLogLevel); + itkGetConstMacro(LogLevel, ElastixLogLevel); + /** Sets an (optional) input mesh. An Update() will transform its points, and store them in the output mesh. */ itkSetConstObjectMacro(InputMesh, MeshType); @@ -288,6 +292,8 @@ class ITK_TEMPLATE_EXPORT TransformixFilter : public ImageSource bool m_LogToConsole{ false }; bool m_LogToFile{ false }; + ElastixLogLevel m_LogLevel{}; + typename MeshType::ConstPointer m_InputMesh{ nullptr }; typename MeshType::Pointer m_OutputMesh{ nullptr }; diff --git a/Core/Main/itkTransformixFilter.hxx b/Core/Main/itkTransformixFilter.hxx index 9b3c41fff..3b77057af 100644 --- a/Core/Main/itkTransformixFilter.hxx +++ b/Core/Main/itkTransformixFilter.hxx @@ -140,7 +140,10 @@ TransformixFilter::GenerateData() const std::string logFileName = m_OutputDirectory + (m_LogFileName.empty() ? "transformix.log" : m_LogFileName); // Setup logging. - const elx::log::guard logGuard(logFileName, m_EnableOutput && m_LogToFile, m_EnableOutput && m_LogToConsole); + const elx::log::guard logGuard(logFileName, + m_EnableOutput && m_LogToFile, + m_EnableOutput && m_LogToConsole, + static_cast(m_LogLevel)); // Instantiate transformix const auto transformixMain = elx::TransformixMain::New();