diff --git a/Modules/BasicImageProcessing/CMakeLists.txt b/Modules/BasicImageProcessing/CMakeLists.txt new file mode 100644 index 0000000000..2f337313f9 --- /dev/null +++ b/Modules/BasicImageProcessing/CMakeLists.txt @@ -0,0 +1,8 @@ +MITK_CREATE_MODULE( + DEPENDS MitkCore + PACKAGE_DEPENDS + PUBLIC + PRIVATE ITK|ITKIOImageBase+ITKIOGDCM +) + +add_subdirectory(MiniApps) diff --git a/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt b/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt new file mode 100644 index 0000000000..e107b85391 --- /dev/null +++ b/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt @@ -0,0 +1,88 @@ +option(BUILD_BasicImageProcessingMiniApps "Build commandline tools for Basic Image Processing" OFF) + +if(BUILD_BasicImageProcessingMiniApps OR MITK_BUILD_ALL_APPS) + + + include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ) + + # list of miniapps + # if an app requires additional dependencies + # they are added after a "^^" and separated by "_" + set( basicImageProcessingMiniApps + FileConverter^^MitkCore + ImageTypeConverter^^MitkCore + ) + + foreach(basicImageProcessingMiniApp ${basicImageProcessingMiniApps}) + # extract mini app name and dependencies + string(REPLACE "^^" "\\;" miniapp_info ${basicImageProcessingMiniApp}) + set(miniapp_info_list ${miniapp_info}) + list(GET miniapp_info_list 0 appname) + list(GET miniapp_info_list 1 raw_dependencies) + string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") + set(dependencies_list ${dependencies}) + + mitk_create_executable(${appname} + DEPENDS MitkCore MitkCommandLine ${dependencies_list} + PACKAGE_DEPENDS ITK + CPP_FILES ${appname}.cpp + ) + # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp + + if(EXECUTABLE_IS_ENABLED) + + # On Linux, create a shell script to start a relocatable application + if(UNIX AND NOT APPLE) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) + endif() + + get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) + + if(APPLE) + if(_is_bundle) + set(_target_locations ${EXECUTABLE_TARGET}.app) + set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) + set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) + set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) + set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) + install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) + else() + if(NOT MACOSX_BUNDLE_NAMES) + set(_qt_conf_install_dirs bin) + set(_target_locations bin/${EXECUTABLE_TARGET}) + set(${_target_locations}_qt_plugins_install_dir bin) + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + else() + foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) + list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) + set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) + list(APPEND _target_locations ${_current_target_location}) + set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) + message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") + + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) + endforeach() + endif() + endif() + else() + set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) + set(${_target_locations}_qt_plugins_install_dir bin) + set(_qt_conf_install_dirs bin) + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + endif() + endif() + endforeach() + + # On Linux, create a shell script to start a relocatable application + if(UNIX AND NOT APPLE) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) + endif() + + if(EXECUTABLE_IS_ENABLED) + MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) + endif() + +endif() diff --git a/Modules/BasicImageProcessing/MiniApps/FileConverter.cpp b/Modules/BasicImageProcessing/MiniApps/FileConverter.cpp new file mode 100644 index 0000000000..c349243f93 --- /dev/null +++ b/Modules/BasicImageProcessing/MiniApps/FileConverter.cpp @@ -0,0 +1,116 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkProperties.h" + +#include "mitkCommandLineParser.h" +#include "mitkIOUtil.h" + +#include + +#include "mitkPreferenceListReaderOptionsFunctor.h" + + +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("File Converter"); + parser.setCategory("Basic Image Processing"); + parser.setDescription(""); + parser.setContributor("MBI"); + + parser.setArgumentPrefix("--","-"); + // Add command line argument names + parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); + parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input file:", "Input File",us::Any(),false); + parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file", us::Any(), false); + parser.addArgument("reader", "r", mitkCommandLineParser::String, "Reader Name", "Reader Name", us::Any()); + parser.addArgument("list-readers", "lr", mitkCommandLineParser::Bool, "Reader Name", "Reader Name", us::Any()); + + + std::map parsedArgs = parser.parseArguments(argc, argv); + + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + // Show a help message + if ( parsedArgs.count("help") || parsedArgs.count("h")) + { + std::cout << parser.helpText(); + return EXIT_SUCCESS; + } + + std::string inputFilename = us::any_cast(parsedArgs["input"]); + std::string outputFilename = us::any_cast(parsedArgs["output"]); + + mitk::PreferenceListReaderOptionsFunctor::ListType preference = {}; + if (parsedArgs.count("reader")) + { + preference.push_back(us::any_cast(parsedArgs["reader"])); + } + + if (parsedArgs.count("list-readers")) + { + mitk::IOUtil::LoadInfo loadInfo(inputFilename); + auto readers = loadInfo.m_ReaderSelector.Get(); + + std::string errMsg; + if (readers.empty()) + { + if (!itksys::SystemTools::FileExists(loadInfo.m_Path.c_str())) + { + errMsg += "File '" + loadInfo.m_Path + "' does not exist\n"; + } + else + { + errMsg += "No reader available for '" + loadInfo.m_Path + "'\n"; + } + MITK_ERROR << errMsg; + return 0; + } + + std::cout << "Available Readers: "< 0) + { + writeName = path + "/" + filename + "_" + std::to_string(count) + extension; + } + mitk::IOUtil::Save(node, writeName); + ++count; + } + + return EXIT_SUCCESS; +} diff --git a/Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp b/Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp new file mode 100644 index 0000000000..080f88e955 --- /dev/null +++ b/Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp @@ -0,0 +1,127 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkCommandLineParser.h" +#include "mitkIOUtil.h" +#include +#include + +#define CONVERT_IMAGE(TYPE, DIM) \ + { \ + MITK_INFO << "Data Type for Conversion: " << typeid(TYPE).name(); \ + itk::Image::Pointer itkImage = itk::Image::New(); \ + mitk::CastToItkImage(image, itkImage); \ + mitk::CastToMitkImage(itkImage, outputImage); \ + } + +#define CONVERT_IMAGE_TYPE(TYPE) \ + { \ + unsigned int dimension = image->GetDimension(); \ + MITK_INFO << "Image Dimension is: " << dimension; \ + switch (dimension) { \ + case 2 : CONVERT_IMAGE( TYPE , 2); \ + break; \ + case 3 : CONVERT_IMAGE( TYPE , 3); \ + break; \ + default: MITK_INFO << "This tool doesn't support a dimension of "< parsedArgs = parser.parseArguments(argc, argv); + + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + // Show a help message + if ( parsedArgs.count("help") || parsedArgs.count("h")) + { + std::cout << parser.helpText(); + return EXIT_SUCCESS; + } + + std::string inputName = us::any_cast(parsedArgs["input"]); + std::string outputName = us::any_cast(parsedArgs["output"]); + std::string type = us::any_cast(parsedArgs["type"]); + + mitk::Image::Pointer image = mitk::IOUtil::Load(inputName); + mitk::Image::Pointer outputImage = mitk::Image::New(); + + if (type.compare("int") == 0) { + CONVERT_IMAGE_TYPE(int); + } + else if (type.compare("uint") == 0) + { + CONVERT_IMAGE_TYPE(unsigned int); + } + else if (type.compare("char") == 0) + { + CONVERT_IMAGE_TYPE(char); + } + else if (type.compare("uchar") == 0) + { + CONVERT_IMAGE_TYPE(unsigned char); + } + else if (type.compare("short") == 0) + { + CONVERT_IMAGE_TYPE(short); + } + else if (type.compare("ushort") == 0) + { + CONVERT_IMAGE_TYPE(unsigned short); + } + else if (type.compare("float") == 0) + { + CONVERT_IMAGE_TYPE(float); + } + else if (type.compare("double") == 0) + { + CONVERT_IMAGE_TYPE(double); + } + else if (type.compare("none") == 0) + { + MITK_INFO << " No conversion performed"; + outputImage = NULL; + } + else + { + CONVERT_IMAGE_TYPE(double); + } + + if (outputImage.IsNotNull()) + { + mitk::IOUtil::Save(outputImage, outputName); + } + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/Modules/BasicImageProcessing/files.cmake b/Modules/BasicImageProcessing/files.cmake new file mode 100644 index 0000000000..562652a41d --- /dev/null +++ b/Modules/BasicImageProcessing/files.cmake @@ -0,0 +1,9 @@ +file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") + +set(CPP_FILES + mitkArithmeticOperation.cpp +) + +set(RESOURCE_FILES + +) diff --git a/Modules/BasicImageProcessing/include/mitkArithmeticOperation.h b/Modules/BasicImageProcessing/include/mitkArithmeticOperation.h new file mode 100644 index 0000000000..7b75ebbd8a --- /dev/null +++ b/Modules/BasicImageProcessing/include/mitkArithmeticOperation.h @@ -0,0 +1,104 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkArithmeticOperation_h +#define mitkArithmeticOperation_h + +#include +#include + +namespace mitk +{ + /** \brief Executes a arithmetic operations on one or two images + * + * All parameters of the arithmetic operations must be specified during construction. + * The actual operation is executed when calling GetResult(). + */ + class MITKBASICIMAGEPROCESSING_EXPORT ArithmeticOperation { + public: + static Image::Pointer Add(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Subtract(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Multiply(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Divide(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + + static Image::Pointer Add(Image::Pointer & imageA, double value, bool outputAsDouble = true); + static Image::Pointer Subtract(Image::Pointer & imageA, double value, bool outputAsDouble = true); + static Image::Pointer Multiply(Image::Pointer & imageA, double value, bool outputAsDouble = true); + static Image::Pointer Divide(Image::Pointer & imageA, double value, bool outputAsDouble = true); + + static Image::Pointer Add(double value, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Subtract(double value, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Multiply(double value, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Divide(double value, Image::Pointer & imageB, bool outputAsDouble = true); + + static Image::Pointer Tan(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Atan(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Cos(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Acos(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Sin(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Asin(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Square(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Sqrt(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Abs(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Exp(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer ExpNeg(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Log10(Image::Pointer & imageA, bool outputAsDouble = true); + }; + + class MITKBASICIMAGEPROCESSING_EXPORT NonStaticArithmeticOperation { + public: + enum OperationsEnum + { + Add2, + Sub2, + Mult, + Div, + AddValue, + SubValue, + MultValue, + DivValue, + PowValue, + Tan, + ATan, + Cos, + ACos, + Sin, + ASin, + Square, + Sqrt, + Abs, + Exp, + ExpNeg, + Log10 + }; + + + void CallExecuteTwoImageFilter(mitk::Image::Pointer imageA, mitk::Image::Pointer imageB); + + template + void ExecuteTwoImageFilter(itk::Image* imageA, itk::Image* imageB); + + template + void ExecuteTwoImageFilterWithFunctor(Image1Type* imageA, Image2Type* imageB); + + mitk::Image::Pointer m_ResultImage; + OperationsEnum m_Algorithm; + bool m_GenerateDoubleOutput = false; + }; + + +} +#endif // mitkArithmeticOperation_h \ No newline at end of file diff --git a/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp b/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp new file mode 100644 index 0000000000..aa4852cd6f --- /dev/null +++ b/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp @@ -0,0 +1,561 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkArithmeticOperation.h" + +#include +#include +#include + +#include +#include +#include "itkUnaryFunctorImageFilter.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace mitk +{ + namespace Functor + { + template< class TInput, class TOutput> + class AddValue + { + public: + AddValue() {}; + ~AddValue() {}; + bool operator!=(const AddValue &) const + { + return false; + } + bool operator==(const AddValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + return A + value; + } + + bool valueLeft = false; + double value = 0.0; + }; + template< class TInput, class TOutput> + class SubValue + { + public: + SubValue() {}; + ~SubValue() {}; + bool operator!=(const SubValue &) const + { + return false; + } + bool operator==(const SubValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + if (valueLeft) + return value - A; + else + return A - value; + } + + bool valueLeft = false; + double value = 0.0; + }; + template< class TInput, class TOutput> + class MultValue + { + public: + MultValue() {}; + ~MultValue() {}; + bool operator!=(const MultValue &) const + { + return false; + } + bool operator==(const MultValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + return A * value; + } + + bool valueLeft = false; + double value = 0.0; + }; + template< class TInput, class TOutput> + class DivValue + { + public: + DivValue() {}; + ~DivValue() {}; + bool operator!=(const DivValue &) const + { + return false; + } + bool operator==(const DivValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + if (valueLeft) + return value / A; + else + return A / value; + } + + bool valueLeft = false; + double value = 1.0; + }; + template< class TInput, class TOutput> + class PowValue + { + public: + PowValue() {}; + ~PowValue() {}; + bool operator!=(const PowValue &) const + { + return false; + } + bool operator==(const PowValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + if (valueLeft) + return std::pow(value, A); + else + return std::pow(A, value); + } + + bool valueLeft = false; + double value = 1.0; + }; + } +} + + +template +static void ExecuteOneImageFilterWithFunctor(ImageType* imageA, double value, bool returnDoubleImage, bool valueLeft, bool , mitk::Image::Pointer & outputImage) +{ + typedef itk::UnaryFunctorImageFilter< ImageType, ImageType, DefaultFunctorType > DefaultFilterType; + typedef itk::UnaryFunctorImageFilter< ImageType, DoubleImageType, DoubleFunctorType > DoubleFilterType; + + if (returnDoubleImage) + { + typename DoubleFilterType::Pointer filter = DoubleFilterType::New(); + filter->SetInput(imageA); + filter->GetFunctor().valueLeft = valueLeft; + filter->GetFunctor().value = value; + filter->Update(); + CastToMitkImage(filter->GetOutput(), outputImage); + } + else + { + typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); + filter->SetInput(imageA); + filter->GetFunctor().valueLeft = valueLeft; + filter->GetFunctor().value = value; + filter->Update(); + CastToMitkImage(filter->GetOutput(), outputImage); + } +} + +template +static void ExecuteOneImageFilterWithFunctorNonParameter(ImageType* imageA, double , bool returnDoubleImage, bool , bool , mitk::Image::Pointer & outputImage) +{ + typedef itk::UnaryFunctorImageFilter< ImageType, ImageType, DefaultFunctorType > DefaultFilterType; + typedef itk::UnaryFunctorImageFilter< ImageType, DoubleImageType, DoubleFunctorType > DoubleFilterType; + + if (returnDoubleImage) + { + typename DoubleFilterType::Pointer filter = DoubleFilterType::New(); + filter->SetInput(imageA); + filter->Update(); + CastToMitkImage(filter->GetOutput(), outputImage); + } + else + { + typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); + filter->SetInput(imageA); + filter->Update(); + CastToMitkImage(filter->GetOutput(), outputImage); + } +} + +template +static void ExecuteOneImageFilter(itk::Image* imageA, double value, bool returnDoubleImage, bool valueLeft, bool parameterFree, mitk::NonStaticArithmeticOperation::OperationsEnum algorithm, mitk::Image::Pointer & outputImage) +{ + typedef itk::Image ImageType; + typedef itk::Image DoubleOutputType; + + + switch (algorithm) { + case mitk::NonStaticArithmeticOperation::OperationsEnum::AddValue: + ExecuteOneImageFilterWithFunctor, + mitk::Functor::AddValue, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::SubValue: + ExecuteOneImageFilterWithFunctor, + mitk::Functor::SubValue, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::MultValue: + ExecuteOneImageFilterWithFunctor, + mitk::Functor::MultValue, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::DivValue: + ExecuteOneImageFilterWithFunctor, + mitk::Functor::DivValue, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::PowValue: + ExecuteOneImageFilterWithFunctor, + mitk::Functor::PowValue, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + + case mitk::NonStaticArithmeticOperation::OperationsEnum::Tan: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Tan, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::ATan: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Atan, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Cos: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Cos, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::ACos: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Acos, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Sin: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Sin, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::ASin: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Asin, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Square: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Square, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Sqrt: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Sqrt, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Abs: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Abs, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Exp: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Exp, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::ExpNeg: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::ExpNegative, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Log10: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Log10, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + default: + break; + } +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Add(Image::Pointer & imageA, Image::Pointer & imageB, bool) +{ + NonStaticArithmeticOperation helper; + helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Add2; + helper.CallExecuteTwoImageFilter(imageA, imageB); + return helper.m_ResultImage; +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Subtract(Image::Pointer & imageA, Image::Pointer & imageB, bool) +{ + NonStaticArithmeticOperation helper; + helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Sub2; + helper.CallExecuteTwoImageFilter(imageA, imageB); + return helper.m_ResultImage; +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Multiply(Image::Pointer & imageA, Image::Pointer & imageB, bool) +{ + NonStaticArithmeticOperation helper; + helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Mult; + helper.CallExecuteTwoImageFilter(imageA, imageB); + return helper.m_ResultImage; +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Divide(Image::Pointer & imageA, Image::Pointer & imageB, bool) +{ + NonStaticArithmeticOperation helper; + helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Div; + helper.CallExecuteTwoImageFilter(imageA, imageB); + return helper.m_ResultImage; +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Add(Image::Pointer & imageA, double value, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::AddValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Subtract(Image::Pointer & imageA, double value, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::SubValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Multiply(Image::Pointer & imageA, double value, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::MultValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Divide(Image::Pointer & imageA, double value, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::DivValue, resultImage)); + return resultImage; +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Add(double value, Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::AddValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Subtract(double value, Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::SubValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Multiply(double value, Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::MultValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Divide(double value, Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::DivValue, resultImage)); + return resultImage; +} + + +mitk::Image::Pointer mitk::ArithmeticOperation::Tan(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Tan, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Atan(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ATan, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Sin(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Sin, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Asin(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ASin, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Cos(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Cos, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Acos(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ACos, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Square(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Square, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Sqrt(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Sqrt, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Abs(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Abs, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Exp(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Exp, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::ExpNeg(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ExpNeg, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Log10(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Log10, resultImage)); + return resultImage; +} + + +void mitk::NonStaticArithmeticOperation::CallExecuteTwoImageFilter(mitk::Image::Pointer imageA, mitk::Image::Pointer imageB) +{ + if (imageA->GetDimension() != imageB->GetDimension()) + { + mitkThrow() << "Image have different dimensions. This is not supported by mitk::ArithmeticOperation"; + } + + switch (imageA->GetDimension()) + { + case 1: + AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 1); + break; + case 2: + AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 2); + break; + case 3: + AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 3); + break; + case 4: + AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 4); + break; + default: + mitkThrow() << "Image Dimension of "<GetDimension() << " is not supported"; + break; + } +} + + +template +void mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter(itk::Image* imageA, itk::Image* imageB) +{ + typedef itk::Image Image1Type; + typedef itk::Image Image2Type; + typedef itk::Image DoubleOutputType; + + + switch (m_Algorithm) { + case OperationsEnum::Add2: + ExecuteTwoImageFilterWithFunctor, + itk::Functor::Add2, + Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); + break; + + case OperationsEnum::Sub2: + ExecuteTwoImageFilterWithFunctor, + itk::Functor::Add2, + Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); + break; + + case OperationsEnum::Mult: + ExecuteTwoImageFilterWithFunctor, + itk::Functor::Add2, + Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); + break; + + case OperationsEnum::Div: + ExecuteTwoImageFilterWithFunctor, + itk::Functor::Add2, + Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); + break; + default: + break; + } +} + +template +void mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilterWithFunctor(Image1Type* imageA, Image2Type* imageB) +{ + typedef itk::BinaryFunctorImageFilter< Image1Type, Image2Type, Image1Type,DefaultFunctorType > DefaultFilterType; + typedef itk::BinaryFunctorImageFilter< Image1Type, Image2Type, DoubleImageType, DoubleFunctorType > DoubleFilterType; + + if (m_GenerateDoubleOutput) + { + typename DoubleFilterType::Pointer filter = DoubleFilterType::New(); + filter->SetInput1(imageA); + filter->SetInput2(imageB); + filter->Update(); + CastToMitkImage(filter->GetOutput(), m_ResultImage); + } + else + { + typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); + filter->SetInput1(imageA); + filter->SetInput2(imageB); + filter->Update(); + CastToMitkImage(filter->GetOutput(), m_ResultImage); + } +} \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CLImageConverter.cpp b/Modules/Classification/CLMiniApps/CLImageConverter.cpp deleted file mode 100644 index de2ab03538..0000000000 --- a/Modules/Classification/CLMiniApps/CLImageConverter.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include "mitkCommandLineParser.h" -#include "mitkIOUtil.h" - -int main(int argc, char* argv[]) -{ - mitkCommandLineParser parser; - - parser.setTitle("Dicom Loader"); - parser.setCategory("Preprocessing Tools"); - parser.setDescription(""); - parser.setContributor("MBI"); - - parser.setArgumentPrefix("--","-"); - // Add command line argument names - parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); - parser.addArgument("input", "i", mitkCommandLineParser::InputDirectory, "Input file:", "Input file",us::Any(),false); - parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file",us::Any(),false); - - std::map parsedArgs = parser.parseArguments(argc, argv); - - if (parsedArgs.size()==0) - return EXIT_FAILURE; - - // Show a help message - if ( parsedArgs.count("help") || parsedArgs.count("h")) - { - std::cout << parser.helpText(); - return EXIT_SUCCESS; - } - - std::string inputName = us::any_cast(parsedArgs["input"]); - std::string outputName = us::any_cast(parsedArgs["output"]); - - mitk::Image::Pointer image = mitk::IOUtil::Load(inputName); - mitk::IOUtil::Save(image, outputName); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CLImageTypeConverter.cpp b/Modules/Classification/CLMiniApps/CLImageTypeConverter.cpp deleted file mode 100644 index aeeaf8325a..0000000000 --- a/Modules/Classification/CLMiniApps/CLImageTypeConverter.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include "mitkCommandLineParser.h" -#include "mitkIOUtil.h" -#include -#include - -#define CONVERT_IMAGE(TYPE, DIM) itk::Image::Pointer itkImage = itk::Image::New(); \ - MITK_INFO << "Data Type for Conversion: "<< typeid(TYPE).name(); \ - mitk::CastToItkImage(image, itkImage); \ - mitk::CastToMitkImage(itkImage, outputImage) - -int main(int argc, char* argv[]) -{ - mitkCommandLineParser parser; - - parser.setTitle("Image Type Converter"); - parser.setCategory("Preprocessing Tools"); - parser.setDescription(""); - parser.setContributor("MBI"); - - parser.setArgumentPrefix("--","-"); - // Add command line argument names - parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); - parser.addArgument("input", "i", mitkCommandLineParser::InputDirectory, "Input file:", "Input file",us::Any(),false); - parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file", us::Any(), false); - parser.addArgument("type", "t", mitkCommandLineParser::OutputFile, "Type definition:", "Define Scalar data type: int, uint, short, ushort, char, uchar, float, double", us::Any(), false); - - std::map parsedArgs = parser.parseArguments(argc, argv); - - if (parsedArgs.size()==0) - return EXIT_FAILURE; - - // Show a help message - if ( parsedArgs.count("help") || parsedArgs.count("h")) - { - std::cout << parser.helpText(); - return EXIT_SUCCESS; - } - - std::string inputName = us::any_cast(parsedArgs["input"]); - std::string outputName = us::any_cast(parsedArgs["output"]); - std::string type = us::any_cast(parsedArgs["type"]); - - mitk::Image::Pointer image = mitk::IOUtil::Load(inputName); - mitk::Image::Pointer outputImage = mitk::Image::New(); - - if (type.compare("int") == 0) - { - CONVERT_IMAGE(int, 3); - } - else if (type.compare("uint") == 0) - { - CONVERT_IMAGE(unsigned int, 3); - } - else if (type.compare("char") == 0) - { - CONVERT_IMAGE(char, 3); - } - else if (type.compare("uchar") == 0) - { - CONVERT_IMAGE(unsigned char, 3); - } - else if (type.compare("short") == 0) - { - CONVERT_IMAGE(short, 3); - } - else if (type.compare("ushort") == 0) - { - CONVERT_IMAGE(unsigned short, 3); - } - else if (type.compare("float") == 0) - { - CONVERT_IMAGE(float, 3); - } - else if (type.compare("double") == 0) - { - CONVERT_IMAGE(double, 3); - } - else if (type.compare("none") == 0) - { - MITK_INFO << " No conversion performed"; - outputImage = image; - } - else - { - CONVERT_IMAGE(double, 3); - } - - - mitk::IOUtil::Save(outputImage, outputName); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CMakeLists.txt b/Modules/Classification/CLMiniApps/CMakeLists.txt index ab24948280..0bb6f5e560 100644 --- a/Modules/Classification/CLMiniApps/CMakeLists.txt +++ b/Modules/Classification/CLMiniApps/CMakeLists.txt @@ -1,143 +1,122 @@ option(BUILD_ClassificationMiniApps "Build commandline tools for classification" OFF) if(BUILD_ClassificationMiniApps OR MITK_BUILD_ALL_APPS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( classificationminiapps RandomForestTraining^^MitkCLVigraRandomForest NativeHeadCTSegmentation^^MitkCLVigraRandomForest ManualSegmentationEvaluation^^MitkCLVigraRandomForest CLScreenshot^^MitkCore_MitkQtWidgetsExt_MitkCLUtilities CLDicom2Nrrd^^MitkCore - CLImageTypeConverter^^MitkCore CLResampleImageToReference^^MitkCore CLGlobalImageFeatures^^MitkCLUtilities_MitkQtWidgetsExt CLMRNormalization^^MitkCLUtilities_MitkCLMRUtilities CLStaple^^MitkCLUtilities CLVoxelFeatures^^MitkCLUtilities CLPolyToNrrd^^ CLPlanarFigureToNrrd^^MitkCore_MitkSegmentation_MitkMultilabel CLSimpleVoxelClassification^^MitkDataCollection_MitkCLVigraRandomForest CLVoxelClassification^^MitkDataCollection_MitkCLImportanceWeighting_MitkCLVigraRandomForest CLBrainMask^^MitkCLUtilities XRaxSimulationFromCT^^MitkCLUtilities CLRandomSampling^^MitkCore_MitkCLUtilities CLRemoveEmptyVoxels^^MitkCore CLN4^^MitkCore CLSkullMask^^MitkCore CLPointSetToSegmentation^^ CLMultiForestPrediction^^MitkDataCollection_MitkCLVigraRandomForest CLNrrdToPoly^^MitkCore CL2Dto3DImage^^MitkCore CLWeighting^^MitkCore_MitkCLImportanceWeighting_MitkCLUtilities CLOverlayRoiCenterOfMass^^MitkCore_MitkCLUtilities_MitkQtWidgetsExt CLLungSegmentation^^MitkCore_MitkSegmentation_MitkMultilabel # RandomForestPrediction^^MitkCLVigraRandomForest ) foreach(classificationminiapps ${classificationminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${classificationminiapps}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} DEPENDS MitkCore MitkCLCore MitkCommandLine ${dependencies_list} PACKAGE_DEPENDS ITK Qt5|Core Vigra CPP_FILES ${appname}.cpp ) # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() # This mini app does not depend on mitkDiffusionImaging at all mitk_create_executable(CLMatchPointReg DEPENDS MitkCore MitkCLUtilities MitkMatchPointRegistration MitkCommandLine MitkMatchPointRegistrationUI PACKAGE_DEPENDS ITK Qt5|Core Vigra MatchPoint CPP_FILES CLMatchPointReg.cpp ) - #mitk_create_executable(CLGlobalImageFeatures - # DEPENDS MitkCore MitkCLUtilities - # CPP_FILES CLGlobalImageFeatures.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLBrainMask - # DEPENDS MitkCore MitkCLUtilities - # CPP_FILES CLBrainMask.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLImageConverter - # DEPENDS MitkCore - # CPP_FILES CLImageConverter.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLSurWeighting - # DEPENDS MitkCore MitkCLUtilities MitkDataCollection #MitkCLImportanceWeighting - # CPP_FILES CLSurWeighting.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLImageCropper - # DEPENDS MitkCore MitkCLUtilities MitkAlgorithmsExt - # CPP_FILES CLImageCropper.cpp mitkCommandLineParser.cpp - #) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/Classification/CLUtilities/files.cmake b/Modules/Classification/CLUtilities/files.cmake index 17b04b392f..64e037b845 100644 --- a/Modules/Classification/CLUtilities/files.cmake +++ b/Modules/Classification/CLUtilities/files.cmake @@ -1,38 +1,39 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkCLResultWritter.cpp Algorithms/itkLabelSampler.cpp Algorithms/itkSmoothedClassProbabilites.cpp Algorithms/mitkRandomImageSampler.cpp Features/itkNeighborhoodFunctorImageFilter.cpp Features/itkLineHistogramBasedMassImageFilter.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp + GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyLevelDifference.cpp GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp GlobalImageFeatures/mitkGIFLocalIntensity.cpp GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp MiniAppUtils/mitkSplitParameterToVector.cpp mitkCLUtil.cpp ) set( TOOL_FILES ) diff --git a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h new file mode 100644 index 0000000000..9f28cde2d6 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h @@ -0,0 +1,156 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkGIFFirstOrderStatistics_h +#define mitkGIFFirstOrderStatistics_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFFirstOrderNumericStatistics : public AbstractGlobalImageFeature + { + public: + /** + * \brief Calculates first order statistics of the given image. + * + * The first order statistics for the intensity distribution within a given Region of Interest (ROI) + * is caluclated. The ROI is defined using a mask. + * + * The features are calculated on a quantified image. If the bin-size is too big, the obtained values + * can be errornous and missleading. It is therefore important to use enough bins. The binned approach is + * used in order to avoid floating-point related errors. + * + * This feature calculator is activated by the option -first-order or -fo. + * + * The connected areas are based on the binned image, the binning parameters can be set via the default + * parameters as described in AbstractGlobalImageFeature. It is also possible to determine the + * dimensionality of the neighbourhood using direction-related commands as described in AbstractGlobalImageFeature. + * No other options are possible beside these two options. + * + * The features are calculated based on a mask. It is assumed that the mask is + * of the type of an unsigned short image. All voxels with the value 1 are treated as masked. + * + * The following features are then defined using the (binned) voxel intensity \f$ x_i \f$ of each voxel, the probability + * an intensity \f$ p_x \f$, and the overall number of voxels within the mask \f$ N_v \f$: + * - First Order::Mean: The mean intensity within the ROI + * \f[ \textup{Mean}= \mu = \frac{1}{N_v} \sum x_i \f] + * - First Order::Unbiased Variance: An unbiased estimation of the variance: + * \f[ \textup{Unbiased Variance} = \frac{1}{N_v - 1} \sum \left( x_i - \mu \right)^2 \f] + * - First Order::Biased Variance: An biased estimation of the variance. If not specified otherwise, this is + * used as the variance: + * \f[ \textup{Biased Variance} = \sigma^2 = \frac{1}{N_v} \sum \left( x_i - \mu \right)^2 \f] + * - First Order::Unbiased Standard Deviation: Estimation of diversity within the intensity values + * \f[ \textup{Unbiased Standard Deviation} = \sqrt{\frac{1}{N_v-1} \sum \left( x_i - \mu \right)^2} \f] + * - First Order::Biased Standard Deviation: Estimation of diversity within the intensity values + * \f[ \textup{Biased Standard Deviation} = \sigma = \sqrt{\frac{1}{N_v} \sum \left( x_i - \mu \right)^2} \f] + * - First Order::Skewness: + * \f[ \textup{Skewness} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^3}{\sigma^3} \f] + * - First Order::Kurtosis: The kurtosis is a measurement of the peakness of the given + * distirbution: + * \f[ \textup{Kurtosis} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^4}{\sigma^4} \f] + * - First Order::Excess Kurtosis: The kurtosis is a measurement of the peakness of the given + * distirbution. The excess kurtosis is similar to the kurtosis, but is corrected by a fisher correction, + * ensuring that a gaussian distribution has an excess kurtosis of 0. + * \f[ \textup{Excess Kurtosis} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^4}{\sigma^4} - 3 \f] + * - First Order::Median: The median is defined as the median of the all intensities in the ROI. + * - First Order::Minimum: The minimum is defined as the minimum of the all intensities in the ROI. + * - First Order::05th Percentile: \f$ P_{5\%} \f$ The 5% percentile. 5% of all voxel do have this or a lower intensity. + * - First Order::10th Percentile: \f$ P_{10\%} \f$ The 10% percentile. 10% of all voxel do have this or a lower intensity. + * - First Order::15th Percentile: \f$ P_{15\%} \f$ The 15% percentile. 15% of all voxel do have this or a lower intensity. + * - First Order::20th Percentile: \f$ P_{20\%} \f$ The 20% percentile. 20% of all voxel do have this or a lower intensity. + * - First Order::25th Percentile: \f$ P_{25\%} \f$ The 25% percentile. 25% of all voxel do have this or a lower intensity. + * - First Order::30th Percentile: \f$ P_{30\%} \f$ The 30% percentile. 30% of all voxel do have this or a lower intensity. + * - First Order::35th Percentile: \f$ P_{35\%} \f$ The 35% percentile. 35% of all voxel do have this or a lower intensity. + * - First Order::40th Percentile: \f$ P_{40\%} \f$ The 40% percentile. 40% of all voxel do have this or a lower intensity. + * - First Order::45th Percentile: \f$ P_{45\%} \f$ The 45% percentile. 45% of all voxel do have this or a lower intensity. + * - First Order::50th Percentile: \f$ P_{50\%} \f$ The 50% percentile. 50% of all voxel do have this or a lower intensity. + * - First Order::55th Percentile: \f$ P_{55\%} \f$ The 55% percentile. 55% of all voxel do have this or a lower intensity. + * - First Order::60th Percentile: \f$ P_{60\%} \f$ The 60% percentile. 60% of all voxel do have this or a lower intensity. + * - First Order::65th Percentile: \f$ P_{65\%} \f$ The 65% percentile. 65% of all voxel do have this or a lower intensity. + * - First Order::70th Percentile: \f$ P_{70\%} \f$ The 70% percentile. 70% of all voxel do have this or a lower intensity. + * - First Order::75th Percentile: \f$ P_{75\%} \f$ The 75% percentile. 75% of all voxel do have this or a lower intensity. + * - First Order::80th Percentile: \f$ P_{80\%} \f$ The 80% percentile. 80% of all voxel do have this or a lower intensity. + * - First Order::85th Percentile: \f$ P_{85\%} \f$ The 85% percentile. 85% of all voxel do have this or a lower intensity. + * - First Order::90th Percentile: \f$ P_{90\%} \f$ The 90% percentile. 90% of all voxel do have this or a lower intensity. + * - First Order::95th Percentile: \f$ P_{95\%} \f$ The 95% percentile. 95% of all voxel do have this or a lower intensity. + * - First Order::Maximum: The maximum is defined as the minimum of the all intensities in the ROI. + * - First Order::Range: The range of intensity values is defined as the difference between the maximum + * and minimum intensity in the ROI. + * - First Order::Interquartile Range: The difference between the 75% and 25% quantile. + * - First Order::Mean Absolute Deviation: The mean absolute deviation gives the mean distance of each + * voxel intensity to the overal mean intensity and is a measure of the dispersion of the intensity form the + * mean value: + * \f[ \textup{Mean Absolute Deviation} = \frac{1}{N_v} \sum \left \| x_i - \mu \right \| \f] + * - First Order::Robust Mean: The mean intensity within the ROI for all voxels between the 10% and 90% quantile: + * \f[ \textup{Robust Mean}= \mu_R = \frac{1}{N_{vr}} \sum x_i \f] + * - First Order::Robust Mean Absolute Deviation: The absolute deviation of all intensities within the ROI for + * all voxels between the 10% and 90% quantilefrom the robust mean intensity: + * \f[ \textup{Robust Mean Absolute Deviation}= \mu_R = \frac{1}{N_{vr}} \sum \left \| x_i - \mu_R \right \| \f] + * - First Order::Median Absolute Deviation: Similar to the mean absolute deviation, but uses the median + * instead of the mean to measure the center of the distribution. + * - First Order::Coefficient Of Variation: Measures the dispersion of the intensity distribution: + * \f[ \textup{Coefficient Of Variation} = \frac{sigma}{\mu} \f] + * - First Order::Quantile Coefficient Of Dispersion: A robust alternative to teh coefficient of variance: + * \f[ \textup{Quantile Coefficient Of Dispersion} = \frac{P_{75\%} - P_{25\%} }{P_{75\%} + P_{25\%}} \f] + * - First Order::Energy: The intensity energy: + * \f[ \textup{Energy} = \sum x_i ^2 \f] + * - First Order::Root Mean Square: Root mean square is an important measure for the error. + * \f[ \textup{Root Mean Square} = \sqrt{\frac{\sum x_i ^2}{N_v}} \f] + * - First Order::Uniformity: + * \f[ \textup{Uniformity} = \sum p_x^2 \f] + * - First Order::Entropy: + * \f[ \textup{Entropy} = - \sum p_x \textup{log}_2(p_x) \f] + * - First Order::Entropy: + * \f[ \textup{Entropy} = - \sum p_x \textup{log}_2(p_x) \f] + * - First Order::Covered Image Intensity Range: Percentage of the image intensity range (maximum - minimum in whole + * image) that is covered by the ROI. + * - First Order::Sum: The sum of all intensities. It is correlated to the mean intensity. + * \f[ \textup{Sum} = \sum x_i \f] + * - First Order::Mode: The most common intensity. + * - First Order::Mode Probability: The likelihood of the most common intensity. + * - First Order::Number Of Voxels: \f$ N_v \f$ the number of voxels covered by the ROI. + * - First Order::Image Dimension: The dimensionality of the image (e.g. 2D, 3D, etc.). + * - First Order::Number Of Voxels: The product of all spacing along all dimensions. In 3D, this is equal to the + * volume. + * - First Order::Number Of Voxels: The volume of a single voxel. If the dimensionality is only 2D, this is the + * surface of an voxel. + */ + mitkClassMacro(GIFFirstOrderNumericStatistics,AbstractGlobalImageFeature) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFFirstOrderNumericStatistics(); + + /** + * \brief Calculates the First Order Features based on a binned version of the image. + */ + FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + FeatureNameListType GetFeatureNames() override; + virtual std::string GetCurrentFeatureEncoding() override; + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + }; +} +#endif //mitkGIFFirstOrderStatistics_h diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp index a50b98f65a..3bb2973578 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp @@ -1,693 +1,693 @@ #include // MITK #include #include #include // ITK #include #include #include // STL #include #include namespace mitk { struct CoocurenceMatrixHolder { public: CoocurenceMatrixHolder(double min, double max, int number); int IntensityToIndex(double intensity); double IndexToMinIntensity(int index); double IndexToMeanIntensity(int index); double IndexToMaxIntensity(int index); double m_MinimumRange; double m_MaximumRange; double m_Stepsize; int m_NumberOfBins; Eigen::MatrixXd m_Matrix; }; struct CoocurenceMatrixFeatures { CoocurenceMatrixFeatures() : JointMaximum(0), JointAverage(0), JointVariance(0), JointEntropy(0), RowMaximum(0), RowAverage(0), RowVariance(0), RowEntropy(0), FirstRowColumnEntropy(0), SecondRowColumnEntropy(0), DifferenceAverage(0), DifferenceVariance(0), DifferenceEntropy(0), SumAverage(0), SumVariance(0), SumEntropy(0), AngularSecondMoment(0), Contrast(0), Dissimilarity(0), InverseDifference(0), InverseDifferenceNormalised(0), InverseDifferenceMoment(0), InverseDifferenceMomentNormalised(0), InverseVariance(0), Correlation(0), Autocorrelation(0), ClusterTendency(0), ClusterShade(0), ClusterProminence(0), FirstMeasureOfInformationCorrelation(0), SecondMeasureOfInformationCorrelation(0) { } public: double JointMaximum; double JointAverage; double JointVariance; double JointEntropy; double RowMaximum; double RowAverage; double RowVariance; double RowEntropy; double FirstRowColumnEntropy; double SecondRowColumnEntropy; double DifferenceAverage; double DifferenceVariance; double DifferenceEntropy; double SumAverage; double SumVariance; double SumEntropy; double AngularSecondMoment; double Contrast; double Dissimilarity; double InverseDifference; double InverseDifferenceNormalised; double InverseDifferenceMoment; double InverseDifferenceMomentNormalised; double InverseVariance; double Correlation; double Autocorrelation; double ClusterTendency; double ClusterShade; double ClusterProminence; double FirstMeasureOfInformationCorrelation; double SecondMeasureOfInformationCorrelation; }; } static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList); static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature); static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number); mitk::CoocurenceMatrixHolder::CoocurenceMatrixHolder(double min, double max, int number) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number) { m_Matrix.resize(number, number); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::CoocurenceMatrixHolder::IntensityToIndex(double intensity) { int index = std::floor((intensity - m_MinimumRange) / m_Stepsize); return std::max(0, std::min(index, m_NumberOfBins - 1)); } double mitk::CoocurenceMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template void CalculateCoOcMatrix(itk::Image* itkImage, itk::Image* mask, itk::Offset offset, int range, mitk::CoocurenceMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef itk::ShapedNeighborhoodIterator ShapeIterType; typedef itk::ShapedNeighborhoodIterator ShapeMaskIterType; typedef itk::ImageRegionConstIterator ConstIterType; typedef itk::ImageRegionConstIterator ConstMaskIterType; itk::Size radius; radius.Fill(range+1); ShapeIterType imageOffsetIter(radius, itkImage, itkImage->GetLargestPossibleRegion()); ShapeMaskIterType maskOffsetIter(radius, mask, mask->GetLargestPossibleRegion()); imageOffsetIter.ActivateOffset(offset); maskOffsetIter.ActivateOffset(offset); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); // iterator.GetIndex() + ci.GetNeighborhoodOffset() auto region = mask->GetLargestPossibleRegion(); while (!maskIter.IsAtEnd()) { auto ciMask = maskOffsetIter.Begin(); auto ciValue = imageOffsetIter.Begin(); if (maskIter.Value() > 0 && ciMask.Get() > 0 && imageIter.Get() == imageIter.Get() && ciValue.Get() == ciValue.Get() && region.IsInside(maskOffsetIter.GetIndex() + ciMask.GetNeighborhoodOffset())) { int i = holder.IntensityToIndex(imageIter.Get()); int j = holder.IntensityToIndex(ciValue.Get()); holder.m_Matrix(i, j) += 1; holder.m_Matrix(j, i) += 1; } ++imageOffsetIter; ++maskOffsetIter; ++imageIter; ++maskIter; } } void CalculateFeatures( mitk::CoocurenceMatrixHolder &holder, mitk::CoocurenceMatrixFeatures & results ) { auto pijMatrix = holder.m_Matrix; auto piMatrix = holder.m_Matrix; auto pjMatrix = holder.m_Matrix; double Ng = holder.m_NumberOfBins; int NgSize = holder.m_NumberOfBins; pijMatrix /= pijMatrix.sum(); piMatrix.rowwise().normalize(); pjMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) for (int j = 0; j < holder.m_NumberOfBins; ++j) { if (pijMatrix(i, j) != pijMatrix(i, j)) pijMatrix(i, j) = 0; if (piMatrix(i, j) != piMatrix(i, j)) piMatrix(i, j) = 0; if (pjMatrix(i, j) != pjMatrix(i, j)) pjMatrix(i, j) = 0; } Eigen::VectorXd piVector = pijMatrix.colwise().sum(); Eigen::VectorXd pjVector = pijMatrix.rowwise().sum(); double sigmai = 0;; for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1;// holder.IndexToMeanIntensity(i); results.RowAverage += iInt * piVector(i); if (piVector(i) > 0) { results.RowEntropy -= piVector(i) * std::log(piVector(i)) / std::log(2); } } for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1; // holder.IndexToMeanIntensity(i); results.RowVariance += (iInt - results.RowAverage)*(iInt - results.RowAverage) * piVector(i); } results.RowMaximum = piVector.maxCoeff(); sigmai = std::sqrt(results.RowVariance); Eigen::VectorXd pimj(NgSize); pimj.fill(0); Eigen::VectorXd pipj(2*NgSize); pipj.fill(0); results.JointMaximum += pijMatrix.maxCoeff(); for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1;// holder.IndexToMeanIntensity(i); double jInt = j + 1;// holder.IndexToMeanIntensity(j); double pij = pijMatrix(i, j); int deltaK = (i - j)>0?(i-j) : (j-i); pimj(deltaK) += pij; pipj(i + j) += pij; results.JointAverage += iInt * pij; if (pij > 0) { results.JointEntropy -= pij * std::log(pij) / std::log(2); results.FirstRowColumnEntropy -= pij * std::log(piVector(i)*pjVector(j)) / std::log(2); } if (piVector(i) > 0 && pjVector(j) > 0 ) { results.SecondRowColumnEntropy -= piVector(i)*pjVector(j) * std::log(piVector(i)*pjVector(j)) / std::log(2); } results.AngularSecondMoment += pij*pij; results.Contrast += (iInt - jInt)* (iInt - jInt) * pij; results.Dissimilarity += std::abs(iInt - jInt) * pij; results.InverseDifference += pij / (1 + (std::abs(iInt - jInt))); results.InverseDifferenceNormalised += pij / (1 + (std::abs(iInt - jInt) / Ng)); results.InverseDifferenceMoment += pij / (1 + (iInt - jInt)*(iInt - jInt)); results.InverseDifferenceMomentNormalised += pij / (1 + (iInt - jInt)*(iInt - jInt)/Ng/Ng); results.Autocorrelation += iInt*jInt * pij; double cluster = (iInt + jInt - 2 * results.RowAverage); results.ClusterTendency += cluster*cluster * pij; results.ClusterShade += cluster*cluster*cluster * pij; results.ClusterProminence += cluster*cluster*cluster*cluster * pij; if (iInt != jInt) { results.InverseVariance += pij / (iInt - jInt) / (iInt - jInt); } } } results.Correlation = 1 / sigmai / sigmai * (-results.RowAverage*results.RowAverage+ results.Autocorrelation); results.FirstMeasureOfInformationCorrelation = (results.JointEntropy - results.FirstRowColumnEntropy) / results.RowEntropy; if (results.JointEntropy < results.SecondRowColumnEntropy) { results.SecondMeasureOfInformationCorrelation = sqrt(1 - exp(-2 * (results.SecondRowColumnEntropy - results.JointEntropy))); } else { results.SecondMeasureOfInformationCorrelation = 0; } for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1; double pij = pijMatrix(i, j); results.JointVariance += (iInt - results.JointAverage)* (iInt - results.JointAverage)*pij; } } for (int k = 0; k < NgSize; ++k) { results.DifferenceAverage += k* pimj(k); if (pimj(k) > 0) { results.DifferenceEntropy -= pimj(k) * log(pimj(k)) / std::log(2); } } for (int k = 0; k < NgSize; ++k) { results.DifferenceVariance += (results.DifferenceAverage-k)* (results.DifferenceAverage-k)*pimj(k); } for (int k = 0; k <2* NgSize ; ++k) { results.SumAverage += (2+k)* pipj(k); if (pipj(k) > 0) { results.SumEntropy -= pipj(k) * log(pipj(k)) / std::log(2); } } for (int k = 0; k < 2*NgSize; ++k) { results.SumVariance += (2+k - results.SumAverage)* (2+k - results.SumAverage)*pipj(k); } //MITK_INFO << std::endl << holder.m_Matrix; //MITK_INFO << std::endl << pijMatrix; //MITK_INFO << std::endl << piMatrix; //MITK_INFO << std::endl << pjMatrix; //for (int i = 0; i < holder.m_NumberOfBins; ++i) //{ // MITK_INFO << "Bin " << i << " Min: " << holder.IndexToMinIntensity(i) << " Max: " << holder.IndexToMaxIntensity(i); //} //MITK_INFO << pimj; //MITK_INFO << pipj; } template void CalculateCoocurenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFCooccurenceMatrix2::FeatureListType & featureList, mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2Configuration config) { typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// double rangeMin = config.MinimumIntensity; double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { offset[i] *= config.range; if (config.direction == i + 2 && offset[i] != 0) { useOffset = false; } } if (useOffset) { offsetVector.push_back(offset); } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; } std::vector resultVector; mitk::CoocurenceMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures overallFeature; for (std::size_t i = 0; i < offsetVector.size(); ++i) { if (config.direction > 1) { if (offsetVector[i][config.direction - 2] != 0) { continue; } } offset = offsetVector[i]; mitk::CoocurenceMatrixHolder holder(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures coocResults; CalculateCoOcMatrix(itkImage, maskImage, offset, config.range, holder); holderOverall.m_Matrix += holder.m_Matrix; CalculateFeatures(holder, coocResults); resultVector.push_back(coocResults); } CalculateFeatures(holderOverall, overallFeature); //NormalizeMatrixFeature(overallFeature, offsetVector.size()); mitk::CoocurenceMatrixFeatures featureMean; mitk::CoocurenceMatrixFeatures featureStd; CalculateMeanAndStdDevFeatures(resultVector, featureMean, featureStd); std::ostringstream ss; ss << config.range; std::string strRange = ss.str(); - MatrixFeaturesTo(overallFeature, config.prefix + " Overall", featureList); - MatrixFeaturesTo(featureMean, config.prefix + " Mean", featureList); - MatrixFeaturesTo(featureStd, config.prefix + " Std.Dev.", featureList); + MatrixFeaturesTo(overallFeature, config.prefix + "Overall ", featureList); + MatrixFeaturesTo(featureMean, config.prefix + "Mean ", featureList); + MatrixFeaturesTo(featureStd, config.prefix + "Std.Dev. ", featureList); } static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList) { featureList.push_back(std::make_pair(prefix + "Joint Maximum", features.JointMaximum)); featureList.push_back(std::make_pair(prefix + "Joint Average", features.JointAverage)); featureList.push_back(std::make_pair(prefix + "Joint Variance", features.JointVariance)); featureList.push_back(std::make_pair(prefix + "Joint Entropy", features.JointEntropy)); - featureList.push_back(std::make_pair(prefix + "Row Maximum", features.RowMaximum)); - featureList.push_back(std::make_pair(prefix + "Row Average", features.RowAverage)); - featureList.push_back(std::make_pair(prefix + "Row Variance", features.RowVariance)); - featureList.push_back(std::make_pair(prefix + "Row Entropy", features.RowEntropy)); - featureList.push_back(std::make_pair(prefix + "First Row-Column Entropy", features.FirstRowColumnEntropy)); - featureList.push_back(std::make_pair(prefix + "Second Row-Column Entropy", features.SecondRowColumnEntropy)); featureList.push_back(std::make_pair(prefix + "Difference Average", features.DifferenceAverage)); featureList.push_back(std::make_pair(prefix + "Difference Variance", features.DifferenceVariance)); featureList.push_back(std::make_pair(prefix + "Difference Entropy", features.DifferenceEntropy)); featureList.push_back(std::make_pair(prefix + "Sum Average", features.SumAverage)); featureList.push_back(std::make_pair(prefix + "Sum Variance", features.SumVariance)); featureList.push_back(std::make_pair(prefix + "Sum Entropy", features.SumEntropy)); featureList.push_back(std::make_pair(prefix + "Angular Second Moment", features.AngularSecondMoment)); featureList.push_back(std::make_pair(prefix + "Contrast", features.Contrast)); featureList.push_back(std::make_pair(prefix + "Dissimilarity", features.Dissimilarity)); featureList.push_back(std::make_pair(prefix + "Inverse Difference", features.InverseDifference)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Normalized", features.InverseDifferenceNormalised)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Moment", features.InverseDifferenceMoment)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Moment Normalized", features.InverseDifferenceMomentNormalised)); - featureList.push_back(std::make_pair(prefix + " Inverse Variance", features.InverseVariance)); + featureList.push_back(std::make_pair(prefix + "Inverse Variance", features.InverseVariance)); featureList.push_back(std::make_pair(prefix + "Correlation", features.Correlation)); - featureList.push_back(std::make_pair(prefix + "Autocorrleation", features.Autocorrelation)); + featureList.push_back(std::make_pair(prefix + "Autocorrelation", features.Autocorrelation)); featureList.push_back(std::make_pair(prefix + "Cluster Tendency", features.ClusterTendency)); featureList.push_back(std::make_pair(prefix + "Cluster Shade", features.ClusterShade)); featureList.push_back(std::make_pair(prefix + "Cluster Prominence", features.ClusterProminence)); featureList.push_back(std::make_pair(prefix + "First Measure of Information Correlation", features.FirstMeasureOfInformationCorrelation)); featureList.push_back(std::make_pair(prefix + "Second Measure of Information Correlation", features.SecondMeasureOfInformationCorrelation)); + featureList.push_back(std::make_pair(prefix + "Row Maximum", features.RowMaximum)); + featureList.push_back(std::make_pair(prefix + "Row Average", features.RowAverage)); + featureList.push_back(std::make_pair(prefix + "Row Variance", features.RowVariance)); + featureList.push_back(std::make_pair(prefix + "Row Entropy", features.RowEntropy)); + featureList.push_back(std::make_pair(prefix + "First Row-Column Entropy", features.FirstRowColumnEntropy)); + featureList.push_back(std::make_pair(prefix + "Second Row-Column Entropy", features.SecondRowColumnEntropy)); } static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature) { #define ADDFEATURE(a) meanFeature.a += featureList[i].a;stdFeature.a += featureList[i].a*featureList[i].a #define CALCVARIANCE(a) stdFeature.a =sqrt(stdFeature.a - meanFeature.a*meanFeature.a) for (std::size_t i = 0; i < featureList.size(); ++i) { ADDFEATURE(JointMaximum); ADDFEATURE(JointAverage); ADDFEATURE(JointVariance); ADDFEATURE(JointEntropy); ADDFEATURE(RowMaximum); ADDFEATURE(RowAverage); ADDFEATURE(RowVariance); ADDFEATURE(RowEntropy); ADDFEATURE(FirstRowColumnEntropy); ADDFEATURE(SecondRowColumnEntropy); ADDFEATURE(DifferenceAverage); ADDFEATURE(DifferenceVariance); ADDFEATURE(DifferenceEntropy); ADDFEATURE(SumAverage); ADDFEATURE(SumVariance); ADDFEATURE(SumEntropy); ADDFEATURE(AngularSecondMoment); ADDFEATURE(Contrast); ADDFEATURE(Dissimilarity); ADDFEATURE(InverseDifference); ADDFEATURE(InverseDifferenceNormalised); ADDFEATURE(InverseDifferenceMoment); ADDFEATURE(InverseDifferenceMomentNormalised); ADDFEATURE(InverseVariance); ADDFEATURE(Correlation); ADDFEATURE(Autocorrelation); ADDFEATURE(ClusterShade); ADDFEATURE(ClusterTendency); ADDFEATURE(ClusterProminence); ADDFEATURE(FirstMeasureOfInformationCorrelation); ADDFEATURE(SecondMeasureOfInformationCorrelation); } NormalizeMatrixFeature(meanFeature, featureList.size()); NormalizeMatrixFeature(stdFeature, featureList.size()); CALCVARIANCE(JointMaximum); CALCVARIANCE(JointAverage); CALCVARIANCE(JointVariance); CALCVARIANCE(JointEntropy); CALCVARIANCE(RowMaximum); CALCVARIANCE(RowAverage); CALCVARIANCE(RowVariance); CALCVARIANCE(RowEntropy); CALCVARIANCE(FirstRowColumnEntropy); CALCVARIANCE(SecondRowColumnEntropy); CALCVARIANCE(DifferenceAverage); CALCVARIANCE(DifferenceVariance); CALCVARIANCE(DifferenceEntropy); CALCVARIANCE(SumAverage); CALCVARIANCE(SumVariance); CALCVARIANCE(SumEntropy); CALCVARIANCE(AngularSecondMoment); CALCVARIANCE(Contrast); CALCVARIANCE(Dissimilarity); CALCVARIANCE(InverseDifference); CALCVARIANCE(InverseDifferenceNormalised); CALCVARIANCE(InverseDifferenceMoment); CALCVARIANCE(InverseDifferenceMomentNormalised); CALCVARIANCE(InverseVariance); CALCVARIANCE(Correlation); CALCVARIANCE(Autocorrelation); CALCVARIANCE(ClusterShade); CALCVARIANCE(ClusterTendency); CALCVARIANCE(ClusterProminence); CALCVARIANCE(FirstMeasureOfInformationCorrelation); CALCVARIANCE(SecondMeasureOfInformationCorrelation); #undef ADDFEATURE #undef CALCVARIANCE } static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number) { features.JointMaximum = features.JointMaximum / number; features.JointAverage = features.JointAverage / number; features.JointVariance = features.JointVariance / number; features.JointEntropy = features.JointEntropy / number; features.RowMaximum = features.RowMaximum / number; features.RowAverage = features.RowAverage / number; features.RowVariance = features.RowVariance / number; features.RowEntropy = features.RowEntropy / number; features.FirstRowColumnEntropy = features.FirstRowColumnEntropy / number; features.SecondRowColumnEntropy = features.SecondRowColumnEntropy / number; features.DifferenceAverage = features.DifferenceAverage / number; features.DifferenceVariance = features.DifferenceVariance / number; features.DifferenceEntropy = features.DifferenceEntropy / number; features.SumAverage = features.SumAverage / number; features.SumVariance = features.SumVariance / number; features.SumEntropy = features.SumEntropy / number; features.AngularSecondMoment = features.AngularSecondMoment / number; features.Contrast = features.Contrast / number; features.Dissimilarity = features.Dissimilarity / number; features.InverseDifference = features.InverseDifference / number; features.InverseDifferenceNormalised = features.InverseDifferenceNormalised / number; features.InverseDifferenceMoment = features.InverseDifferenceMoment / number; features.InverseDifferenceMomentNormalised = features.InverseDifferenceMomentNormalised / number; features.InverseVariance = features.InverseVariance / number; features.Correlation = features.Correlation / number; features.Autocorrelation = features.Autocorrelation / number; features.ClusterShade = features.ClusterShade / number; features.ClusterTendency = features.ClusterTendency / number; features.ClusterProminence = features.ClusterProminence / number; features.FirstMeasureOfInformationCorrelation = features.FirstMeasureOfInformationCorrelation / number; features.SecondMeasureOfInformationCorrelation = features.SecondMeasureOfInformationCorrelation / number; } mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2(): m_Range(1.0) { SetShortName("cooc2"); SetLongName("cooccurence2"); SetFeatureClassName("Co-occurenced Based Features"); } mitk::GIFCooccurenceMatrix2::FeatureListType mitk::GIFCooccurenceMatrix2::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { InitializeQuantifier(image, mask); FeatureListType featureList; GIFCooccurenceMatrix2Configuration config; config.direction = GetDirection(); config.range = m_Range; config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); config.prefix = FeatureDescriptionPrefix(); AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,config); return featureList; } mitk::GIFCooccurenceMatrix2::FeatureNameListType mitk::GIFCooccurenceMatrix2::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFCooccurenceMatrix2::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); parser.addArgument(name+"::range", name+"::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); AddQuantifierArguments(parser); } void mitk::GIFCooccurenceMatrix2::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); if (parsedArgs.count(GetLongName())) { InitializeQuantifierFromParameters(feature, maskNoNAN); std::vector ranges; if (parsedArgs.count(name + "::range")) { ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); } else { ranges.push_back(1); } for (std::size_t i = 0; i < ranges.size(); ++i) { MITK_INFO << "Start calculating coocurence with range " << ranges[i] << "...."; this->SetRange(ranges[i]); auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating coocurence with range " << ranges[i] << "...."; } } } std::string mitk::GIFCooccurenceMatrix2::GetCurrentFeatureEncoding() { std::ostringstream ss; ss << m_Range; std::string strRange = ss.str(); return QuantifierParameterString() + "_Range-" + ss.str(); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp new file mode 100644 index 0000000000..38f3a7ad77 --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp @@ -0,0 +1,357 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// MITK +#include +#include +#include + +// ITK +#include +#include +#include + +// STL +#include + +struct FirstOrderNumericParameterStruct { + mitk::IntensityQuantifier::Pointer quantifier; + double MinimumIntensity; + double MaximumIntensity; + int Bins; + std::string prefix; +}; + +template +void +CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderNumericStatistics::FeatureListType & featureList, FirstOrderNumericParameterStruct params) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + + typename MaskType::Pointer maskImage = MaskType::New(); + mitk::CastToItkImage(mask, maskImage); + + // + // Calculate the Volume of Voxel (Maximum to the 3th order) + // + double voxelVolume = 1; + for (unsigned int i = 0; i < std::min(3, VImageDimension); ++i) + voxelVolume *= itkImage->GetSpacing()[i]; + + // + // Calculate the Hypervolume of Voxel + // + double voxelSpace = 1; + for (unsigned int i = 0; i < VImageDimension; ++i) + voxelSpace *= itkImage->GetSpacing()[i]; + + unsigned int numberOfBins = params.quantifier->GetBins(); + std::vector histogram; + histogram.resize(numberOfBins, 0); + + + double minimum = std::numeric_limits::max(); + double maximum = std::numeric_limits::lowest(); + double absoluteMinimum = std::numeric_limits::max(); + double absoluteMaximum = std::numeric_limits::lowest(); + double sum = 0; + double sumTwo= 0; + double sumThree = 0; + unsigned int numberOfVoxels = 0; + + itk::ImageRegionIterator imageIter(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionIterator maskIter(maskImage, maskImage->GetLargestPossibleRegion()); + + while (!imageIter.IsAtEnd()) + { + double value = imageIter.Get(); + + absoluteMinimum = std::min(minimum, value); + absoluteMaximum = std::max(maximum, value); + if (maskIter.Get() > 0) + { + minimum = std::min(minimum, value); + maximum = std::max(maximum, value); + + sum += value; + sumTwo += value * value; + sumThree += value * value*value; + + histogram[params.quantifier->IntensityToIndex(value)] += 1; + + ++numberOfVoxels; + } + ++maskIter; + ++imageIter; + } + + // + // Histogram based calculations + // + unsigned int passedValues = 0; + double doubleNoOfVoxes = numberOfVoxels; + double median = 0; + double lastIntensityWithValues = params.quantifier->IndexToMeanIntensity(0); + std::size_t modeIdx = 0; + + double entropy = 0; + double uniformity = 0; + + std::vector percentiles; + percentiles.resize(20, 0); + + for (std::size_t idx = 0; idx < histogram.size(); ++idx) + { + unsigned int actualValues = histogram[idx]; + + for (std::size_t percentileIdx = 0; percentileIdx < percentiles.size(); ++percentileIdx) + { + double threshold = doubleNoOfVoxes * (percentileIdx + 1) *1.0 / (percentiles.size()); + if ((passedValues < threshold) & ((passedValues + actualValues) >= threshold)) + { + // Lower Bound + if (passedValues == std::floor(threshold)) + { + percentiles[percentileIdx] = 0.5*(lastIntensityWithValues + params.quantifier->IndexToMeanIntensity(idx)); + } + else + { + percentiles[percentileIdx] = params.quantifier->IndexToMeanIntensity(idx); + } + } + } + + if ((passedValues < doubleNoOfVoxes * 0.5) & ((passedValues + actualValues) >= doubleNoOfVoxes * 0.5)) + { + // Lower Bound + if (passedValues == std::floor(doubleNoOfVoxes * 0.5)) + { + median = 0.5*(lastIntensityWithValues + params.quantifier->IndexToMeanIntensity(idx)); + } + else + { + median = params.quantifier->IndexToMeanIntensity(idx); + } + } + + if (actualValues > histogram[modeIdx]) + { + modeIdx = idx; + } + + if (actualValues > 0) + { + lastIntensityWithValues = params.quantifier->IndexToMeanIntensity(idx); + + double currentProbability = actualValues / (1.0 *numberOfVoxels); + uniformity += currentProbability * currentProbability; + entropy += currentProbability * std::log(currentProbability) / std::log(2); + } + passedValues += actualValues; + } + double p10 = percentiles[1]; + double p25idx = params.quantifier->IntensityToIndex(percentiles[4]); + double p75idx = params.quantifier->IntensityToIndex(percentiles[14]); + double p90 = percentiles[17]; + + double mean = sum / (numberOfVoxels); + double variance = sumTwo / (numberOfVoxels) - (mean*mean); + double energy = sumTwo; + double rootMeanSquare = std::sqrt(sumTwo / numberOfVoxels); + + double sumAbsoluteDistanceToMean = 0; + double sumAbsoluteDistanceToMedian = 0; + double sumRobust = 0; + double sumRobustSquare = 0; + double sumRobustAbsolulteDistanceToMean = 0; + double sumValueMinusMean = 0; + double sumValueMinusMeanThree = 0; + double sumValueMinusMeanFour = 0; + unsigned int numberOfRobustVoxel = 0; + + + maskIter.GoToBegin(); + imageIter.GoToBegin(); + while (!imageIter.IsAtEnd()) + { + if (maskIter.Get() > 0) + { + double value = imageIter.Get(); + double valueMinusMean = value - mean; + + sumAbsoluteDistanceToMean += std::abs(valueMinusMean); + sumAbsoluteDistanceToMedian += std::abs(value - median); + sumValueMinusMean += valueMinusMean; + sumValueMinusMeanThree += valueMinusMean * valueMinusMean * valueMinusMean; + sumValueMinusMeanFour += valueMinusMean * valueMinusMean * valueMinusMean * valueMinusMean; + + if ((p10 <= value) & (value <= p90)) + { + sumRobust += value; + sumRobustSquare += value * value; + ++numberOfRobustVoxel; + } + } + ++maskIter; + ++imageIter; + } + double robustMean = sumRobust / numberOfRobustVoxel; + double robustVariance = sumRobustSquare / numberOfRobustVoxel - (robustMean * robustMean); + + maskIter.GoToBegin(); + imageIter.GoToBegin(); + while (!imageIter.IsAtEnd()) + { + if (maskIter.Get() > 0) + { + double value = imageIter.Get(); + + if ((p10 <= value) & (value <= p90)) + { + sumRobustAbsolulteDistanceToMean += std::abs(value - robustMean); + } + } + ++maskIter; + ++imageIter; + } + + + + double meanAbsoluteDeviation = sumAbsoluteDistanceToMean / numberOfVoxels; + double medianAbsoluteDeviation = sumAbsoluteDistanceToMedian / numberOfVoxels; + double robustMeanAbsoluteDeviation = sumRobustAbsolulteDistanceToMean / numberOfRobustVoxel; + double skewness = sumValueMinusMeanThree / numberOfVoxels / variance / std::sqrt(variance); + double kurtosis = sumValueMinusMeanFour / numberOfVoxels / variance / variance; + double interquantileRange = p75idx - p25idx; + double coefficientOfVariation = std::sqrt(variance) / mean; + double quantileCoefficientOfDispersion = (p75idx - p25idx) / (p75idx + p25idx + 2); + double coveredImageRange = (maximum - minimum)/ (absoluteMaximum - absoluteMinimum) ; + + featureList.push_back(std::make_pair(params.prefix + "Mean", mean)); + featureList.push_back(std::make_pair(params.prefix + "Variance", variance)); + featureList.push_back(std::make_pair(params.prefix + "Skewness", skewness)); + featureList.push_back(std::make_pair(params.prefix + "Excess kurtosis", kurtosis-3)); + featureList.push_back(std::make_pair(params.prefix + "Median", median)); + featureList.push_back(std::make_pair(params.prefix + "Minimum", minimum)); + featureList.push_back(std::make_pair(params.prefix + "05th Percentile", percentiles[0])); + featureList.push_back(std::make_pair(params.prefix + "10th Percentile", percentiles[1])); + featureList.push_back(std::make_pair(params.prefix + "15th Percentile", percentiles[2])); + featureList.push_back(std::make_pair(params.prefix + "20th Percentile", percentiles[3])); + featureList.push_back(std::make_pair(params.prefix + "25th Percentile", percentiles[4])); + featureList.push_back(std::make_pair(params.prefix + "30th Percentile", percentiles[5])); + featureList.push_back(std::make_pair(params.prefix + "35th Percentile", percentiles[6])); + featureList.push_back(std::make_pair(params.prefix + "40th Percentile", percentiles[7])); + featureList.push_back(std::make_pair(params.prefix + "45th Percentile", percentiles[8])); + featureList.push_back(std::make_pair(params.prefix + "50th Percentile", percentiles[9])); + featureList.push_back(std::make_pair(params.prefix + "55th Percentile", percentiles[10])); + featureList.push_back(std::make_pair(params.prefix + "60th Percentile", percentiles[11])); + featureList.push_back(std::make_pair(params.prefix + "65th Percentile", percentiles[12])); + featureList.push_back(std::make_pair(params.prefix + "70th Percentile", percentiles[13])); + featureList.push_back(std::make_pair(params.prefix + "75th Percentile", percentiles[14])); + featureList.push_back(std::make_pair(params.prefix + "80th Percentile", percentiles[15])); + featureList.push_back(std::make_pair(params.prefix + "85th Percentile", percentiles[16])); + featureList.push_back(std::make_pair(params.prefix + "90th Percentile", percentiles[17])); + featureList.push_back(std::make_pair(params.prefix + "95th Percentile", percentiles[18])); + featureList.push_back(std::make_pair(params.prefix + "Maximum", maximum)); + featureList.push_back(std::make_pair(params.prefix + "Interquantile range", interquantileRange)); + featureList.push_back(std::make_pair(params.prefix + "Range", maximum-minimum)); + featureList.push_back(std::make_pair(params.prefix + "Mean absolute deviation", meanAbsoluteDeviation)); + featureList.push_back(std::make_pair(params.prefix + "Robust mean absolute deviation", robustMeanAbsoluteDeviation)); + featureList.push_back(std::make_pair(params.prefix + "Median absolute deviation", medianAbsoluteDeviation)); + featureList.push_back(std::make_pair(params.prefix + "Coefficient of variation", coefficientOfVariation)); + featureList.push_back(std::make_pair(params.prefix + "Quantile coefficient of dispersion", quantileCoefficientOfDispersion)); + featureList.push_back(std::make_pair(params.prefix + "Energy", energy)); + featureList.push_back(std::make_pair(params.prefix + "Root mean square", rootMeanSquare)); + + featureList.push_back(std::make_pair(params.prefix + "Standard Deviation", std::sqrt(variance))); + featureList.push_back(std::make_pair(params.prefix + "Kurtosis", kurtosis)); + featureList.push_back(std::make_pair(params.prefix + "Robust mean", robustMean)); + featureList.push_back(std::make_pair(params.prefix + "Robust variance", robustVariance)); + featureList.push_back(std::make_pair(params.prefix + "Covered image intensity range", coveredImageRange)); + featureList.push_back(std::make_pair(params.prefix + "Mode index", modeIdx)); + featureList.push_back(std::make_pair(params.prefix + "Mode value", params.quantifier->IndexToMeanIntensity(modeIdx))); + featureList.push_back(std::make_pair(params.prefix + "Mode probability", histogram[modeIdx] / (1.0*numberOfVoxels))); + featureList.push_back(std::make_pair(params.prefix + "Entropy", entropy)); + featureList.push_back(std::make_pair(params.prefix + "Uniformtiy", uniformity)); + featureList.push_back(std::make_pair(params.prefix + "Number of voxels", numberOfVoxels)); + featureList.push_back(std::make_pair(params.prefix + "Sum of voxels", sum)); + featureList.push_back(std::make_pair(params.prefix + "Voxel space", voxelSpace)); + featureList.push_back(std::make_pair(params.prefix + "Voxel volume", voxelVolume)); + featureList.push_back(std::make_pair(params.prefix + "Image Dimension", VImageDimension)); + + return; +} + +mitk::GIFFirstOrderNumericStatistics::GIFFirstOrderNumericStatistics() +{ + SetShortName("fon"); + SetLongName("first-order-numeric"); + SetFeatureClassName("First Order Numeric"); +} + +mitk::GIFFirstOrderNumericStatistics::FeatureListType mitk::GIFFirstOrderNumericStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + InitializeQuantifier(image, mask); + FeatureListType featureList; + + FirstOrderNumericParameterStruct params; + + params.quantifier = GetQuantifier(); + params.MinimumIntensity = GetQuantifier()->GetMinimum(); + params.MaximumIntensity = GetQuantifier()->GetMaximum(); + params.Bins = GetQuantifier()->GetBins(); + params.prefix = FeatureDescriptionPrefix(); + AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); + + return featureList; +} + +mitk::GIFFirstOrderNumericStatistics::FeatureNameListType mitk::GIFFirstOrderNumericStatistics::GetFeatureNames() +{ + FeatureNameListType featureList; + return featureList; +} + + +void mitk::GIFFirstOrderNumericStatistics::AddArguments(mitkCommandLineParser &parser) +{ + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use First Order Statistic (Numeric)", "calculates First Order Statistic (Numeric)", us::Any()); + AddQuantifierArguments(parser); +} + +void +mitk::GIFFirstOrderNumericStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +{ + auto parsedArgs = GetParameter(); + if (parsedArgs.count(GetLongName())) + { + InitializeQuantifierFromParameters(feature, maskNoNAN); + MITK_INFO << "Start calculating first order features ...."; + auto localResults = this->CalculateFeatures(feature, maskNoNAN); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating first order features...."; + } +} + +std::string mitk::GIFFirstOrderNumericStatistics::GetCurrentFeatureEncoding() +{ + return QuantifierParameterString(); +} \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp index d29b4a9e0e..a531a1043d 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp @@ -1,173 +1,173 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include // MITK #include #include #include #include // ITK #include #include // STL #include struct GIFIntensityVolumeHistogramFeaturesParameters { mitk::IntensityQuantifier::Pointer quantifier; std::string prefix; }; template static void CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, GIFIntensityVolumeHistogramFeaturesParameters params, mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType & featureList) { typedef itk::Image ImageType; typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); mitk::IntensityQuantifier::Pointer quantifier = params.quantifier; std::string prefix = params.prefix; itk::ImageRegionConstIterator iter(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIterator iterMask(itkMask, itkMask->GetLargestPossibleRegion()); MITK_INFO << "Quantification: " << quantifier->GetMinimum() << " to " << quantifier->GetMaximum() << " with " << quantifier->GetBins()<< " bins"; iter.GoToBegin(); iterMask.GoToBegin(); std::vector hist; hist.resize(quantifier->GetBins() , 0); int count = 0; while (!iter.IsAtEnd()) { if (iterMask.Get() > 0) { double value = iter.Get(); //std::size_t index = std::floor((value - minimum) / (maximum - minimum) * (bins-1)); std::size_t index = quantifier->IntensityToIndex(value); ++count; hist[index] += 1.0;// / count; } ++iterMask; ++iter; } bool notFoundIntenstiy010 = true; bool notFoundIntenstiy090 = true; double intensity010 = -1; double intensity090 = -1; double fraction = 0; double auc = 0; bool firstRound = true; for (int i = quantifier->GetBins()-1; i >= 0; --i) { hist[i] /= count; hist[i] += fraction; fraction = hist[i]; if (!firstRound) { auc += 0.5 * (hist[i] + hist[i+1]) / (quantifier->GetBins()-1); } firstRound = false; if (notFoundIntenstiy010 && fraction > 0.1) { intensity010 = quantifier->IndexToMeanIntensity(i + 1); notFoundIntenstiy010 = false; } if (notFoundIntenstiy090 && fraction > 0.9) { intensity090 = quantifier->IndexToMeanIntensity(i + 1); notFoundIntenstiy090 = false; } } unsigned int index010 = std::ceil(quantifier->GetBins() * 0.1); unsigned int index090 = std::floor(quantifier->GetBins() * 0.9); - featureList.push_back(std::make_pair(prefix + "Volume fration at 0.10 intensity", hist[index010])); - featureList.push_back(std::make_pair(prefix + "Volume fration at 0.90 intensity", hist[index090])); + featureList.push_back(std::make_pair(prefix + "Volume fraction at 0.10 intensity", hist[index010])); + featureList.push_back(std::make_pair(prefix + "Volume fraction at 0.90 intensity", hist[index090])); featureList.push_back(std::make_pair(prefix + "Intensity at 0.10 volume", intensity010)); featureList.push_back(std::make_pair(prefix + "Intensity at 0.90 volume", intensity090)); - featureList.push_back(std::make_pair(prefix + "Difference volume fration at 0.10 and 0.90 intensity", std::abs(hist[index010] - hist[index090]))); + featureList.push_back(std::make_pair(prefix + "Difference volume fraction at 0.10 and 0.90 intensity", std::abs(hist[index010] - hist[index090]))); featureList.push_back(std::make_pair(prefix + "Difference intensity at 0.10 and 0.90 volume", std::abs(intensity090 - intensity010))); featureList.push_back(std::make_pair(prefix + "Area under IVH curve", auc)); //featureList.push_back(std::make_pair("Local Intensity Global Intensity Peak", globalPeakValue)); } mitk::GIFIntensityVolumeHistogramFeatures::GIFIntensityVolumeHistogramFeatures() { SetLongName("intensity-volume-histogram"); SetShortName("ivoh"); SetFeatureClassName("Intensity Volume Histogram"); } mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { InitializeQuantifier(image, mask, 1000); FeatureListType featureList; GIFIntensityVolumeHistogramFeaturesParameters params; params.quantifier = GetQuantifier(); params.prefix = FeatureDescriptionPrefix(); AccessByItk_3(image, CalculateIntensityPeak, mask, params, featureList); return featureList; } mitk::GIFIntensityVolumeHistogramFeatures::FeatureNameListType mitk::GIFIntensityVolumeHistogramFeatures::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFIntensityVolumeHistogramFeatures::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Local Intensity", "calculates local intensity based features", us::Any()); AddQuantifierArguments(parser); } void mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) { InitializeQuantifierFromParameters(feature, mask, 1000); auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating local intensity features ...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating local intensity features...."; } } std::string mitk::GIFIntensityVolumeHistogramFeatures::GetCurrentFeatureEncoding() { return QuantifierParameterString(); } diff --git a/Modules/Classification/CLUtilities/test/files.cmake b/Modules/Classification/CLUtilities/test/files.cmake index b0f32b97fe..579c0e0670 100644 --- a/Modules/Classification/CLUtilities/test/files.cmake +++ b/Modules/Classification/CLUtilities/test/files.cmake @@ -1,14 +1,18 @@ set(MODULE_TESTS + mitkGIFCooc2Test mitkGIFCurvatureStatisticTest mitkGIFFirstOrderHistogramStatisticsTest + mitkGIFFirstOrderNumericStatisticsTest + mitkGIFFirstOrderStatisticsTest mitkGIFGreyLevelDistanceZoneTest mitkGIFGreyLevelSizeZoneTest mitkGIFImageDescriptionFeaturesTest + mitkGIFIntensityVolumeHistogramTest mitkGIFLocalIntensityTest mitkGIFNeighbourhoodGreyToneDifferenceFeaturesTest mitkGIFNeighbouringGreyLevelDependenceFeatureTest mitkGIFVolumetricDensityStatisticsTest mitkGIFVolumetricStatisticsTest #mitkSmoothedClassProbabilitesTest.cpp #mitkGlobalFeaturesTest.cpp ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFCooc2Test.cpp b/Modules/Classification/CLUtilities/test/mitkGIFCooc2Test.cpp new file mode 100644 index 0000000000..ef4dcd4254 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFCooc2Test.cpp @@ -0,0 +1,251 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include +#include "mitkIOUtil.h" +#include + +#include + +class mitkGIFCooc2TestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFCooc2TestSuite); + + MITK_TEST(ImageDescription_PhantomTest_3D); + MITK_TEST(ImageDescription_PhantomTest_2D); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_IBSI_Phantom_Image_Small; + mitk::Image::Pointer m_IBSI_Phantom_Image_Large; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; + +public: + + void setUp(void) override + { + m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); + m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); + m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); + m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); + } + + void ImageDescription_PhantomTest_3D() + { + mitk::GIFCooccurenceMatrix2::Pointer featureCalculator = mitk::GIFCooccurenceMatrix2::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 18 features.", std::size_t(93), featureList.size()); + + // These values are obtained with IBSI (3D Comb) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Maximum with Large IBSI Phantom Image", 0.509, results["Co-occurenced Based Features::Overall Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Average with Large IBSI Phantom Image", 2.149, results["Co-occurenced Based Features::Overall Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Variance with Large IBSI Phantom Image", 3.132, results["Co-occurenced Based Features::Overall Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Entropy with Large IBSI Phantom Image", 2.574, results["Co-occurenced Based Features::Overall Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Average with Large IBSI Phantom Image", 1.379, results["Co-occurenced Based Features::Overall Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Variance with Large IBSI Phantom Image", 3.215, results["Co-occurenced Based Features::Overall Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Entropy with Large IBSI Phantom Image", 1.641, results["Co-occurenced Based Features::Overall Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Average with Large IBSI Phantom Image", 4.298, results["Co-occurenced Based Features::Overall Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Variance with Large IBSI Phantom Image", 7.412, results["Co-occurenced Based Features::Overall Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Entropy with Large IBSI Phantom Image", 2.110, results["Co-occurenced Based Features::Overall Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Angular Second Moment with Large IBSI Phantom Image", 0.291, results["Co-occurenced Based Features::Overall Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Contrast with Large IBSI Phantom Image", 5.118, results["Co-occurenced Based Features::Overall Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Dissimilarity with Large IBSI Phantom Image", 1.380, results["Co-occurenced Based Features::Overall Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference with Large IBSI Phantom Image", 0.688, results["Co-occurenced Based Features::Overall Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Normalized with Large IBSI Phantom Image", 0.856, results["Co-occurenced Based Features::Overall Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Moment with Large IBSI Phantom Image", 0.631, results["Co-occurenced Based Features::Overall Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.902, results["Co-occurenced Based Features::Overall Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Variance with Large IBSI Phantom Image", 0.057, results["Co-occurenced Based Features::Overall Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Correlation with Large IBSI Phantom Image", 0.183, results["Co-occurenced Based Features::Overall Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Autocorrelation with Large IBSI Phantom Image", 5.192, results["Co-occurenced Based Features::Overall Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Tendency with Large IBSI Phantom Image", 7.412, results["Co-occurenced Based Features::Overall Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Shade with Large IBSI Phantom Image", 17.419, results["Co-occurenced Based Features::Overall Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Prominence with Large IBSI Phantom Image", 147.464, results["Co-occurenced Based Features::Overall Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall First Measure of Information Correlation with Large IBSI Phantom Image", -0.0288, results["Co-occurenced Based Features::Overall First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Second Measure of Information Correlation with Large IBSI Phantom Image", 0.269, results["Co-occurenced Based Features::Overall Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Maximum with Large IBSI Phantom Image", 0.679, results["Co-occurenced Based Features::Overall Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Average with Large IBSI Phantom Image", 2.149, results["Co-occurenced Based Features::Overall Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Variance with Large IBSI Phantom Image", 3.132, results["Co-occurenced Based Features::Overall Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Entropy with Large IBSI Phantom Image", 1.306, results["Co-occurenced Based Features::Overall Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall First Row-Column Entropy with Large IBSI Phantom Image", 2.611, results["Co-occurenced Based Features::Overall First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Second Row-Column Entropy with Large IBSI Phantom Image", 2.611, results["Co-occurenced Based Features::Overall Second Row-Column Entropy"], 0.001); + + + + + // These values are obtained with IBSI (3D Avg) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Maximum with Large IBSI Phantom Image", 0.503, results["Co-occurenced Based Features::Mean Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Average with Large IBSI Phantom Image", 2.143, results["Co-occurenced Based Features::Mean Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Variance with Large IBSI Phantom Image", 3.099, results["Co-occurenced Based Features::Mean Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Entropy with Large IBSI Phantom Image", 2.399, results["Co-occurenced Based Features::Mean Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Average with Large IBSI Phantom Image", 1.431, results["Co-occurenced Based Features::Mean Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Variance with Large IBSI Phantom Image", 3.056, results["Co-occurenced Based Features::Mean Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Entropy with Large IBSI Phantom Image", 1.563, results["Co-occurenced Based Features::Mean Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Average with Large IBSI Phantom Image", 4.2859, results["Co-occurenced Based Features::Mean Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Variance with Large IBSI Phantom Image", 7.072, results["Co-occurenced Based Features::Mean Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Entropy with Large IBSI Phantom Image", 1.9226, results["Co-occurenced Based Features::Mean Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Angular Second Moment with Large IBSI Phantom Image", 0.303, results["Co-occurenced Based Features::Mean Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Contrast with Large IBSI Phantom Image", 5.3245, results["Co-occurenced Based Features::Mean Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Dissimilarity with Large IBSI Phantom Image", 1.431, results["Co-occurenced Based Features::Mean Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference with Large IBSI Phantom Image", 0.6766, results["Co-occurenced Based Features::Mean Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Normalized with Large IBSI Phantom Image", 0.8506, results["Co-occurenced Based Features::Mean Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Moment with Large IBSI Phantom Image", 0.6177, results["Co-occurenced Based Features::Mean Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.8984, results["Co-occurenced Based Features::Mean Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Variance with Large IBSI Phantom Image", 0.0604, results["Co-occurenced Based Features::Mean Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Correlation with Large IBSI Phantom Image", 0.157, results["Co-occurenced Based Features::Mean Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Autocorrelation with Large IBSI Phantom Image", 5.05544, results["Co-occurenced Based Features::Mean Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Tendency with Large IBSI Phantom Image", 7.0728, results["Co-occurenced Based Features::Mean Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Shade with Large IBSI Phantom Image", 16.6441, results["Co-occurenced Based Features::Mean Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Prominence with Large IBSI Phantom Image", 144.703, results["Co-occurenced Based Features::Mean Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean First Measure of Information Correlation with Large IBSI Phantom Image", -0.15684, results["Co-occurenced Based Features::Mean First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Second Measure of Information Correlation with Large IBSI Phantom Image", 0.519588, results["Co-occurenced Based Features::Mean Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Maximum with Large IBSI Phantom Image", 0.6808, results["Co-occurenced Based Features::Mean Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Average with Large IBSI Phantom Image", 2.143, results["Co-occurenced Based Features::Mean Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Variance with Large IBSI Phantom Image", 3.0993, results["Co-occurenced Based Features::Mean Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Entropy with Large IBSI Phantom Image", 1.29699, results["Co-occurenced Based Features::Mean Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean First Row-Column Entropy with Large IBSI Phantom Image", 2.5939, results["Co-occurenced Based Features::Mean First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Second Row-Column Entropy with Large IBSI Phantom Image", 2.5939, results["Co-occurenced Based Features::Mean Second Row-Column Entropy"], 0.001); + } + + void ImageDescription_PhantomTest_2D() + { + mitk::GIFCooccurenceMatrix2::Pointer featureCalculator = mitk::GIFCooccurenceMatrix2::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 558 features.", std::size_t(558), featureList.size()); + + // These values are obtained with IBSI + // Standard accuracy is 0.01 + // These values are obtained with IBSI (2D Comb) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Maximum with Large IBSI Phantom Image", 0.512, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Average with Large IBSI Phantom Image", 2.143, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Variance with Large IBSI Phantom Image", 2.7115, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Entropy with Large IBSI Phantom Image", 2.2383, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Average with Large IBSI Phantom Image", 1.3990, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Variance with Large IBSI Phantom Image", 3.06426, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Entropy with Large IBSI Phantom Image", 1.49262, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Average with Large IBSI Phantom Image", 4.28686, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Variance with Large IBSI Phantom Image", 5.65615, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Entropy with Large IBSI Phantom Image", 1.79494, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Angular Second Moment with Large IBSI Phantom Image", 0.351678, results["SliceWise Mean Co-occurenced Based Features::Overall Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Contrast with Large IBSI Phantom Image", 5.19019, results["SliceWise Mean Co-occurenced Based Features::Overall Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Dissimilarity with Large IBSI Phantom Image", 1.3990, results["SliceWise Mean Co-occurenced Based Features::Overall Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference with Large IBSI Phantom Image", 0.683294, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Normalized with Large IBSI Phantom Image", 0.8538, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment with Large IBSI Phantom Image", 0.625003, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.90088, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Variance with Large IBSI Phantom Image", 0.055286, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Correlation with Large IBSI Phantom Image", 0.0173072, results["SliceWise Mean Co-occurenced Based Features::Overall Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Autocorrelation with Large IBSI Phantom Image", 5.13953, results["SliceWise Mean Co-occurenced Based Features::Overall Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Tendency with Large IBSI Phantom Image", 5.6561, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Shade with Large IBSI Phantom Image", 6.97661, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Prominence with Large IBSI Phantom Image", 80.3855, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall First Measure of Information Correlation with Large IBSI Phantom Image", -0.0340891, results["SliceWise Mean Co-occurenced Based Features::Overall First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Second Measure of Information Correlation with Large IBSI Phantom Image", 0.2625, results["SliceWise Mean Co-occurenced Based Features::Overall Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Maximum with Large IBSI Phantom Image", 0.682689, results["SliceWise Mean Co-occurenced Based Features::Overall Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Average with Large IBSI Phantom Image", 2.14343, results["SliceWise Mean Co-occurenced Based Features::Overall Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Variance with Large IBSI Phantom Image", 2.71158, results["SliceWise Mean Co-occurenced Based Features::Overall Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Entropy with Large IBSI Phantom Image", 1.13773, results["SliceWise Mean Co-occurenced Based Features::Overall Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall First Row-Column Entropy with Large IBSI Phantom Image", 2.27545, results["SliceWise Mean Co-occurenced Based Features::Overall First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Second Row-Column Entropy with Large IBSI Phantom Image", 2.27545, results["SliceWise Mean Co-occurenced Based Features::Overall Second Row-Column Entropy"], 0.001); + + + + + // These values are obtained with IBSI (2D Avg) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Maximum with Large IBSI Phantom Image", 0.5188, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Average with Large IBSI Phantom Image", 2.14242, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Variance with Large IBSI Phantom Image", 2.6877, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Entropy with Large IBSI Phantom Image", 2.04966, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Average with Large IBSI Phantom Image", 1.42247, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Variance with Large IBSI Phantom Image", 2.90159, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Entropy with Large IBSI Phantom Image", 1.39615, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Average with Large IBSI Phantom Image", 4.28484, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Variance with Large IBSI Phantom Image", 5.47293, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Entropy with Large IBSI Phantom Image", 1.60319, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Angular Second Moment with Large IBSI Phantom Image", 0.367529, results["SliceWise Mean Co-occurenced Based Features::Mean Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Contrast with Large IBSI Phantom Image", 5.27785, results["SliceWise Mean Co-occurenced Based Features::Mean Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Dissimilarity with Large IBSI Phantom Image", 1.42247, results["SliceWise Mean Co-occurenced Based Features::Mean Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference with Large IBSI Phantom Image", 0.677949, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Normalized with Large IBSI Phantom Image", 0.851399, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment with Large IBSI Phantom Image", 0.618737, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.899219, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Variance with Large IBSI Phantom Image", 0.0566983, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Correlation with Large IBSI Phantom Image", -.012107, results["SliceWise Mean Co-occurenced Based Features::Mean Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Autocorrelation with Large IBSI Phantom Image", 5.09437, results["SliceWise Mean Co-occurenced Based Features::Mean Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Tendency with Large IBSI Phantom Image", 5.47293, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Shade with Large IBSI Phantom Image", 6.99782, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Prominence with Large IBSI Phantom Image", 79.1126, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean First Measure of Information Correlation with Large IBSI Phantom Image", -0.15512, results["SliceWise Mean Co-occurenced Based Features::Mean First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Second Measure of Information Correlation with Large IBSI Phantom Image", 0.487457, results["SliceWise Mean Co-occurenced Based Features::Mean Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Maximum with Large IBSI Phantom Image", 0.689717, results["SliceWise Mean Co-occurenced Based Features::Mean Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Average with Large IBSI Phantom Image", 2.14242, results["SliceWise Mean Co-occurenced Based Features::Mean Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Variance with Large IBSI Phantom Image", 2.6877, results["SliceWise Mean Co-occurenced Based Features::Mean Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Entropy with Large IBSI Phantom Image", 1.1238, results["SliceWise Mean Co-occurenced Based Features::Mean Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean First Row-Column Entropy with Large IBSI Phantom Image", 2.24761, results["SliceWise Mean Co-occurenced Based Features::Mean First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Second Row-Column Entropy with Large IBSI Phantom Image", 2.24761, results["SliceWise Mean Co-occurenced Based Features::Mean Second Row-Column Entropy"], 0.001); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFCooc2 ) \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp new file mode 100644 index 0000000000..31bac39039 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp @@ -0,0 +1,113 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include +#include "mitkIOUtil.h" +#include + +#include + +class mitkGIFFirstOrderNumericStatisticsTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFFirstOrderNumericStatisticsTestSuite); + + MITK_TEST(ImageDescription_PhantomTest); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_IBSI_Phantom_Image_Small; + mitk::Image::Pointer m_IBSI_Phantom_Image_Large; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; + +public: + + void setUp(void) override + { + m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); + m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); + m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); + m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); + } + + void ImageDescription_PhantomTest() + { + mitk::GIFFirstOrderNumericStatistics::Pointer featureCalculator = mitk::GIFFirstOrderNumericStatistics::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 50 features.", std::size_t(50), featureList.size()); + + // These values are obtained by a run of the filter. + // The might be wrong! + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean with Large IBSI Phantom Image", 2.15, results["First Order Numeric::Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Variance with Large IBSI Phantom Image", 3.05, results["First Order Numeric::Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Skewness with Large IBSI Phantom Image", 1.08, results["First Order Numeric::Skewness"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Excess kurtosis with Large IBSI Phantom Image", -0.355, results["First Order Numeric::Excess kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median with Large IBSI Phantom Image", 1, results["First Order Numeric::Median"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Minimum with Large IBSI Phantom Image", 1, results["First Order Numeric::Minimum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::10th Percentile with Large IBSI Phantom Image", 1, results["First Order Numeric::10th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::90th Percentile with Large IBSI Phantom Image", 4, results["First Order Numeric::90th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Maximum with Large IBSI Phantom Image", 6, results["First Order Numeric::Maximum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Interquantile range with Large IBSI Phantom Image", 3, results["First Order Numeric::Interquantile range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Range with Large IBSI Phantom Image", 5, results["First Order Numeric::Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean absolute deviation with Large IBSI Phantom Image", 1.55, results["First Order Numeric::Mean absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean absolute deviation with Large IBSI Phantom Image", 1.11, results["First Order Numeric::Robust mean absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median absolute deviation with Large IBSI Phantom Image", 1.15, results["First Order Numeric::Median absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order Numeric::Coefficient of variation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.6, results["First Order Numeric::Quantile coefficient of dispersion"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Energy with Large IBSI Phantom Image", 567, results["First Order Numeric::Energy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order Numeric::Root mean square"], 0.01); + + + // These values are taken from the IBSI Initiative to ensure compatibility + // The values are given with an accuracy of 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Standard Deviation with Large IBSI Phantom Image", 1.74513, results["First Order Numeric::Standard Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Kurtosis with Large IBSI Phantom Image", 2.64538, results["First Order Numeric::Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order Numeric::Robust mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust variance with Large IBSI Phantom Image", 1.65204, results["First Order Numeric::Robust variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Covered image intensity range with Large IBSI Phantom Image", 0.83333, results["First Order Numeric::Covered image intensity range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode index with Large IBSI Phantom Image",0 , results["First Order Numeric::Mode index"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode value with Large IBSI Phantom Image", 1, results["First Order Numeric::Mode value"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode probability with Large IBSI Phantom Image", 0.675676, results["First Order Numeric::Mode probability"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Entropy with Large IBSI Phantom Image", -1.26561, results["First Order Numeric::Entropy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Uniformtiy with Large IBSI Phantom Image", 0.512418, results["First Order Numeric::Uniformtiy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Number of voxels with Large IBSI Phantom Image", 74 , results["First Order Numeric::Number of voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order Numeric::Sum of voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel space with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel space"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel volume with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel volume"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Image Dimension with Large IBSI Phantom Image", 3, results["First Order Numeric::Image Dimension"], 0.01); + + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderNumericStatistics ) \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp new file mode 100644 index 0000000000..d6af72b9a8 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp @@ -0,0 +1,112 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include +#include "mitkIOUtil.h" +#include + +#include + +class mitkGIFFirstOrderStatisticsTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFFirstOrderStatisticsTestSuite); + + MITK_TEST(ImageDescription_PhantomTest); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_IBSI_Phantom_Image_Small; + mitk::Image::Pointer m_IBSI_Phantom_Image_Large; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; + +public: + + void setUp(void) override + { + m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); + m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); + m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); + m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); + } + + void ImageDescription_PhantomTest() + { + mitk::GIFFirstOrderStatistics::Pointer featureCalculator = mitk::GIFFirstOrderStatistics::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 50 features.", std::size_t(50), featureList.size()); + + // These values are obtained by a run of the filter. + // The might be wrong! + + + // These values are taken from the IBSI Initiative to ensure compatibility + // The values are given with an accuracy of 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mean with Large IBSI Phantom Image", 2.15, results["First Order::Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Unbiased Variance with Large IBSI Phantom Image", 3.09, results["First Order::Unbiased Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Biased Variance with Large IBSI Phantom Image", 3.05, results["First Order::Biased Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Skewness with Large IBSI Phantom Image", 1.08, results["First Order::Skewness"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Kurtosis with Large IBSI Phantom Image", 2.65, results["First Order::Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Median with Large IBSI Phantom Image", 1, results["First Order::Median"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Minimum with Large IBSI Phantom Image", 1, results["First Order::Minimum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Maximum with Large IBSI Phantom Image", 6, results["First Order::Maximum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Range with Large IBSI Phantom Image", 5, results["First Order::Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mean Absolute Deviation with Large IBSI Phantom Image", 1.55, results["First Order::Mean Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Robust Mean Absolute Deviation with Large IBSI Phantom Image", 1.11, results["First Order::Robust Mean Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Median Absolute Deviation with Large IBSI Phantom Image", 1.15, results["First Order::Median Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order::Coefficient Of Variation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.625, results["First Order::Quantile Coefficient Of Dispersion"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Energy with Large IBSI Phantom Image", 567, results["First Order::Energy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order::Root Mean Square"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Entropy with Large IBSI Phantom Image", 1.26561, results["First Order::Entropy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Excess Kurtosis with Large IBSI Phantom Image", -0.35462, results["First Order::Excess Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Covered image intensity range with Large IBSI Phantom Image", 0.5555555, results["First Order::Covered Image Intensity Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order::Sum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mode with Large IBSI Phantom Image", 1, results["First Order::Mode"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mode Probability with Large IBSI Phantom Image", 50, results["First Order::Mode Probability"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Unbiased Standard deviation with Large IBSI Phantom Image", 1.757, results["First Order::Unbiased Standard deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Biased Standard deviation with Large IBSI Phantom Image", 1.74627, results["First Order::Biased Standard deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order::Robust Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Number Of Voxels with Large IBSI Phantom Image", 74, results["First Order::Number Of Voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::10th Percentile with Large IBSI Phantom Image", 0.648, results["First Order::10th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::90th Percentile with Large IBSI Phantom Image", 4.475, results["First Order::90th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Interquantile Range with Large IBSI Phantom Image", 2.91125, results["First Order::Interquartile Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Voxel Space with Large IBSI Phantom Image", 8, results["First Order::Voxel Space"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Voxel Volume with Large IBSI Phantom Image", 8, results["First Order::Voxel Volume"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Image Dimension with Large IBSI Phantom Image", 3, results["First Order::Image Dimension"], 0.01); + + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderStatistics ) \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp new file mode 100644 index 0000000000..b0a0eebfa0 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp @@ -0,0 +1,159 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include +#include "mitkIOUtil.h" +#include + +#include + +class mitkGIFIntensityVolumeHistogramTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE( mitkGIFIntensityVolumeHistogramTestSuite); + + MITK_TEST(ImageDescription_PhantomTest_Large); + MITK_TEST(ImageDescription_PhantomTest_Small); + MITK_TEST(ImageDescription_PhantomTest_2D); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_IBSI_Phantom_Image_Small; + mitk::Image::Pointer m_IBSI_Phantom_Image_Large; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; + +public: + + void setUp(void) override + { + m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); + m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); + m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); + m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); + } + + void ImageDescription_PhantomTest_Large() + { + mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 7 features.", std::size_t(7), featureList.size()); + + + // These values are obtained in cooperation with IBSI + // Reported with an accuracy of 0.1 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.3243, results["Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.09459, results["Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 5, results["Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.22973, results["Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 3, results["Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.32027, results["Intensity Volume Histogram::Area under IVH curve"], 0.001); + } + + void ImageDescription_PhantomTest_Small() + { + mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Small, m_IBSI_Phantom_Mask_Small); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 7 features.", std::size_t(7), featureList.size()); + + + // These values are obtained in cooperation with IBSI + // Reported with an accuracy of 0.1 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.3243, results["Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.09459, results["Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 5, results["Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.22973, results["Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 3, results["Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.32027, results["Intensity Volume Histogram::Area under IVH curve"], 0.001); + } + + void ImageDescription_PhantomTest_2D() + { + mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 42 features.", std::size_t(42), featureList.size()); + + + // These values are obtained by calculating on the features + // Could be wrong! + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.31539, results["SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.0924106, results["SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 6, results["SliceWise Mean Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["SliceWise Mean Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.222979, results["SliceWise Mean Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 4, results["SliceWise Mean Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.314325, results["SliceWise Mean Intensity Volume Histogram::Area under IVH curve"], 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.0248178, results["SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.00149203, results["SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 1, results["SliceWise Var. Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 0, results["SliceWise Var. Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.01414, results["SliceWise Var. Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 1, results["SliceWise Var. Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.0110923, results["SliceWise Var. Intensity Volume Histogram::Area under IVH curve"], 0.001); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFIntensityVolumeHistogram) \ No newline at end of file diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index 8ac0be92e5..89c06dd6e0 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,77 +1,78 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(MITK_MODULES Core CommandLine AppUtil RDF LegacyIO DataTypesExt Annotation LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMReaderServices DICOMTesting SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction SceneSerialization Gizmo GraphAlgorithms Multilabel ImageStatistics ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation QtWidgets QtWidgetsExt Chart SegmentationUI MatchPointRegistration MatchPointRegistrationUI Classification GPGPU OpenIGTLink IGTBase IGT CameraCalibration OpenCL OpenCVVideoSupport QtOverlays ToFHardware ToFProcessing ToFUI PhotoacousticsHardware PhotoacousticsAlgorithms PhotoacousticsLib US USUI DicomUI Remeshing Python QtPython Persistence OpenIGTLinkUI IGTUI DicomRT RTUI IOExt XNAT TubeGraph BiophotonicsHardware DiffusionImaging TumorInvasionAnalysis BoundingShape RenderWindowManager RenderWindowManagerUI CEST + BasicImageProcessing ) if(MITK_ENABLE_PIC_READER) list(APPEND MITK_MODULES IpPicSupportIO) endif()