diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fb6818..e1f5817 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,304 +1,304 @@ #----------------------------------------------------------------------------- # This is the root RTToolbox CMakeList file. #----------------------------------------------------------------------------- PROJECT(RTToolbox) CMAKE_MINIMUM_REQUIRED(VERSION 3.1) # RTToolbox version number. -SET(RTToolbox_VERSION_MAJOR "4") -SET(RTToolbox_VERSION_MINOR "1") -SET(RTToolbox_VERSION_PATCH "2") +SET(RTToolbox_VERSION_MAJOR "5") +SET(RTToolbox_VERSION_MINOR "0") +SET(RTToolbox_VERSION_PATCH "0") # Version string should not include patch level. The major.minor is # enough to distinguish available features of the toolbox. SET(RTToolbox_VERSION_STRING "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}") SET(RTToolbox_FULL_VERSION_STRING "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}.${RTToolbox_VERSION_PATCH}") # default build type SET(CMAKE_BUILD_TYPE Release) MARK_AS_ADVANCED(BUILD_SHARED_LIBS) IF (WIN32) IF (MSVC_VERSION LESS 1600) MESSAGE(FATAL_ERROR "RTToolbox requires at least Visual Studio 2010.") ENDIF(MSVC_VERSION LESS 1600) add_definitions(-D_SCL_SECURE_NO_WARNINGS) ELSE (WIN32) IF (CMAKE_COMPILER_IS_GNUCC) IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 5.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0) MESSAGE(AUTHOR_WARNING "RTToolbox was only tested with GCC 4.6 and GCC 4.9. You are using GCC " ${CMAKE_CXX_COMPILER_VERSION} ". This compiler version might not work.") ENDIF() ENDIF() ENDIF(WIN32) IF(COMMAND CMAKE_POLICY) # Enable old CMake behaviour when dealing with export_library_dependencies(). # This is necessary to avoid warnings in CMake versions # greater than 3.0 # See http://www.cmake.org/cmake/help/v3.0/policy/CMP0033.html CMAKE_POLICY(SET CMP0033 OLD) IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.2) # See https://cmake.org/cmake/help/v3.3/policy/CMP0062.html CMAKE_POLICY(SET CMP0062 OLD) ENDIF() ENDIF(COMMAND CMAKE_POLICY) #----------------------------------------------------------------------------- # CMake Function(s) and Macro(s) #----------------------------------------------------------------------------- include(cmake/MacroParseArguments.cmake) include(cmake/rttbMacroCreateModuleConf.cmake) include(cmake/rttbMacroCreateModule.cmake) include(cmake/rttbMacroCreateApplication.cmake) include(cmake/rttbMacroCheckModule.cmake) include(cmake/rttbMacroUseModule.cmake) include(cmake/rttbMacroCreateTestModule.cmake) include(cmake/rttbFunctionOrganizeSources.cmake) include(cmake/rttbMacroCreateApplicationTests.cmake) #----------------------------------------------------------------------------- # Basis config RTTB module infrastructure #----------------------------------------------------------------------------- set(RTTB_MODULES_CONF_DIR ${RTToolbox_BINARY_DIR}/modulesConf CACHE INTERNAL "Modules Conf") set(RTTB_MODULES_PACKAGE_DEPENDS_DIR ${RTToolbox_SOURCE_DIR}/cmake/PackageDepends) set(MODULES_PACKAGE_DEPENDS_DIRS ${RTTB_MODULES_PACKAGE_DEPENDS_DIR}) #----------------------------------------------------------------------------- # Testing setup # Configure Dart testing support. This should be done before any # MESSAGE(FATAL_ERROR ...) commands are invoked. #----------------------------------------------------------------------------- SET(CTEST_NEW_FORMAT 1) INCLUDE(CTest) ENABLE_TESTING() IF(BUILD_TESTING) CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/cmake/RemoveTemporaryFiles.cmake.in ${RTToolbox_BINARY_DIR}/cmake/RemoveTemporaryFiles.cmake @ONLY IMMEDIATE) CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/cmake/rttbSampleBuildTest.cmake.in ${RTToolbox_BINARY_DIR}/cmake/rttbSampleBuildTest.cmake @ONLY) CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/cmake/CTestCustom.ctest.in ${RTToolbox_BINARY_DIR}/cmake/CTestCustom.ctest @ONLY) FILE(WRITE ${RTToolbox_BINARY_DIR}/CTestCustom.cmake "INCLUDE(\"${RTToolbox_BINARY_DIR}/cmake/CTestCustom.ctest\")\n") SET(BUILDNAME "${BUILDNAME}" CACHE STRING "Name of build on the dashboard") MARK_AS_ADVANCED(BUILDNAME) ENDIF(BUILD_TESTING) #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- IF(NOT LIBRARY_OUTPUT_PATH) SET (LIBRARY_OUTPUT_PATH ${RTToolbox_BINARY_DIR}/bin CACHE PATH "Single output directory for building all libraries.") ENDIF(NOT LIBRARY_OUTPUT_PATH) IF(NOT EXECUTABLE_OUTPUT_PATH) SET (EXECUTABLE_OUTPUT_PATH ${RTToolbox_BINARY_DIR}/bin CACHE PATH "Single output directory for building all executables.") ENDIF(NOT EXECUTABLE_OUTPUT_PATH) MARK_AS_ADVANCED(EXECUTABLE_OUTPUT_PATH LIBRARY_OUTPUT_PATH) MARK_AS_ADVANCED(LIBRARY_OUTPUT_PATH EXECUTABLE_OUTPUT_PATH) SET(RTToolbox_LIBRARY_PATH "${LIBRARY_OUTPUT_PATH}") SET(RTToolbox_EXECUTABLE_PATH "${EXECUTABLE_OUTPUT_PATH}") #----------------------------------------------------------------------------- # Find Doxygen. #----------------------------------------------------------------------------- FIND_PROGRAM(DOXYGEN_EXECUTABLE "doxygen") #----------------------------------------------------------------------------- # Installation vars. # RTToolbox_INSTALL_BIN_DIR - binary dir (executables) # RTToolbox_INSTALL_LIB_DIR - library dir (libs) # RTToolbox_INSTALL_INCLUDE_DIR - include dir (headers) # RTToolbox_INSTALL_NO_DEVELOPMENT - do not install development files # RTToolbox_INSTALL_NO_RUNTIME - do not install runtime files # RTToolbox_INSTALL_NO_DOCUMENTATION - do not install documentation files # Remark: needs directory are stored with no leading slash (CMake 2.4 and newer) #----------------------------------------------------------------------------- IF(NOT RTTOOLBOX_INSTALL_BIN_DIR) SET(RTTOOLBOX_INSTALL_BIN_DIR "bin") ENDIF(NOT RTTOOLBOX_INSTALL_BIN_DIR) IF(NOT RTTOOLBOX_INSTALL_LIB_DIR) SET(RTTOOLBOX_INSTALL_LIB_DIR "lib") ENDIF(NOT RTTOOLBOX_INSTALL_LIB_DIR) IF(NOT RTTOOLBOX_INSTALL_PACKAGE_DIR) SET(RTTOOLBOX_INSTALL_PACKAGE_DIR "lib") ENDIF(NOT RTTOOLBOX_INSTALL_PACKAGE_DIR) IF(NOT RTTOOLBOX_INSTALL_INCLUDE_DIR) SET(RTTOOLBOX_INSTALL_INCLUDE_DIR "include") ENDIF(NOT RTTOOLBOX_INSTALL_INCLUDE_DIR) IF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) SET(RTTOOLBOX_INSTALL_NO_DEVELOPMENT 0) ENDIF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) IF(NOT RTTOOLBOX_INSTALL_NO_RUNTIME) SET(RTTOOLBOX_INSTALL_NO_RUNTIME 0) ENDIF(NOT RTTOOLBOX_INSTALL_NO_RUNTIME) IF(NOT RTTOOLBOX_INSTALL_NO_DOCUMENTATION) SET(RTTOOLBOX_INSTALL_NO_DOCUMENTATION 0) ENDIF(NOT RTTOOLBOX_INSTALL_NO_DOCUMENTATION) SET(RTTOOLBOX_INSTALL_NO_LIBRARIES) IF(RTTOOLBOX_BUILD_SHARED_LIBS) IF(RTTOOLBOX_INSTALL_NO_RUNTIME AND RTTOOLBOX_INSTALL_NO_DEVELOPMENT) SET(RTTOOLBOX_INSTALL_NO_LIBRARIES 1) ENDIF(RTTOOLBOX_INSTALL_NO_RUNTIME AND RTTOOLBOX_INSTALL_NO_DEVELOPMENT) ELSE(RTTOOLBOX_BUILD_SHARED_LIBS) IF(RTTOOLBOX_INSTALL_NO_DEVELOPMENT) SET(RTTOOLBOX_INSTALL_NO_LIBRARIES 1) ENDIF(RTTOOLBOX_INSTALL_NO_DEVELOPMENT) ENDIF(RTTOOLBOX_BUILD_SHARED_LIBS) # set RTToolbox_DIR so it can be used by subprojects SET(RTToolbox_DIR "${CMAKE_BINARY_DIR}" CACHE INTERNAL "RTToolbox dir to be used by subprojects") #----------------------------------------------------------------------------- # DCMTK MT-Flag treat #----------------------------------------------------------------------------- option(RTTB_DCMTK_COMPLIANCE_ENFORCE_MT "This enforces the whole RTToolbox to be compiled with /MT,/MTd to be compliant with DCMTK" OFF) string(FIND ${CMAKE_GENERATOR} "Visual Studio" RTTB_VS_USED) if(RTTB_DCMTK_COMPLIANCE_ENFORCE_MT AND RTTB_VS_USED EQUAL 0) message(STATUS "Enforce DCMTK compliance: /MT and /MTd flags are used") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) message(STATUS "CMAKE_C_FLAGS_DEBUG set to: ${CMAKE_C_FLAGS_DEBUG}") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE}) message(STATUS "CMAKE_C_FLAGS_RELEASE set to: ${CMAKE_C_FLAGS_RELEASE}") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL}) message(STATUS "CMAKE_C_FLAGS_MINSIZEREL set to: ${CMAKE_C_FLAGS_MINSIZEREL}") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO}) message(STATUS "CMAKE_C_FLAGS_RELWITHDEBINFO set to: ${CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) message(STATUS "CMAKE_CXX_FLAGS_DEBUG set to: ${CMAKE_CXX_FLAGS_DEBUG}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) message(STATUS "CMAKE_CXX_FLAGS_RELEASE set to: ${CMAKE_CXX_FLAGS_RELEASE}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL}) message(STATUS "CMAKE_CXX_FLAGS_MINSIZEREL set to: ${CMAKE_CXX_FLAGS_MINSIZEREL}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) message(STATUS "CMAKE_CXX_FLAGS_RELWITHDEBINFO set to: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") endif() #----------------------------------------------------------------------------- # Advanced RTToolbox configuration #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # RTToolbox build configuration options. IF (WIN32) OPTION(BUILD_SHARED_LIBS "Build RTToolbox with shared libraries." OFF) ELSE (WIN32) OPTION(BUILD_SHARED_LIBS "Build RTToolbox with shared libraries." ON) ENDIF (WIN32) OPTION (RTTB_VIRTUOS_SUPPORT "Build RTToolbox with Virtuos support." OFF) IF (RTTB_VIRTUOS_SUPPORT) SET(RTToolbox_VIRTUOS_SUPPORT "1") ELSE() SET(RTToolbox_VIRTUOS_SUPPORT "0") ENDIF() IF(NOT BUILD_SHARED_LIBS) IF(UNIX) MESSAGE(FATAL_ERROR "RTToolbox currently does not support a static build on unix like systems. We are working on that...") ENDIF(UNIX) ENDIF(NOT BUILD_SHARED_LIBS) SET(RTTB_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) IF(NOT RTToolbox_NO_LIBRARY_VERSION) # This setting of SOVERSION assumes that any API change # will increment either the minor or major version number of RTToolbox. SET(RTToolbox_LIBRARY_PROPERTIES VERSION "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}.${RTToolbox_VERSION_PATCH}" SOVERSION "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}" ) ENDIF(NOT RTToolbox_NO_LIBRARY_VERSION) #----------------------------------------------------------------------------- # Configure files with settings for use by the build. # #----------------------------------------------------------------------------- CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/RTToolboxConfigure.h.in ${RTToolbox_BINARY_DIR}/RTToolboxConfigure.h) IF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) INSTALL(FILES ${RTToolbox_BINARY_DIR}/RTToolboxConfigure.h DESTINATION ${RTTOOLBOX_INSTALL_INCLUDE_DIR} COMPONENT Development) ENDIF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) #----------------------------------------------------------------------------- # The entire RTToolbox tree should use the same include path #----------------------------------------------------------------------------- #Default include dir. Others dirs will be defined by activated subprojects INCLUDE_DIRECTORIES(${RTToolbox_BINARY_DIR}) LINK_DIRECTORIES(${LIBARY_OUTPUT_PATH}) #Prepare the correct target information export by the subprojects SET(RTToolbox_TARGETS_FILE "${RTToolbox_BINARY_DIR}/RTToolboxTargets.cmake") FILE(WRITE ${RTToolbox_TARGETS_FILE} "# Generated by CMake, do not edit!") #----------------------------------------------------------------------------- # Dispatch the build into the proper subdirectories. #----------------------------------------------------------------------------- OPTION(BUILD_Apps "Determine if the CLI applications will be generated." ON) MESSAGE (STATUS "generating Project RTToolbox") ADD_SUBDIRECTORY (code) IF (BUILD_Apps) ADD_SUBDIRECTORY (apps) ENDIF() IF (BUILD_TESTING) ADD_SUBDIRECTORY (testing) ENDIF (BUILD_TESTING) ADD_SUBDIRECTORY (documentation) #----------------------------------------------------------------------------- # Help other projects use RTToolbox. #----------------------------------------------------------------------------- EXPORT(PACKAGE RTToolbox) # Copy the UseRTToolbox.cmake file to the binary tree for backward compatability. CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/UseRTToolbox.cmake.in ${RTToolbox_BINARY_DIR}/UseRTToolbox.cmake COPYONLY IMMEDIATE) # Save library dependencies. EXPORT_LIBRARY_DEPENDENCIES(${RTToolbox_BINARY_DIR}/RTToolboxLibraryDepends.cmake) # Create the RTToolboxConfig.cmake file containing the RTToolbox configuration. INCLUDE (${RTToolbox_SOURCE_DIR}/rttbGenerateRTToolboxConfig.cmake) IF(NOT RTToolbox_INSTALL_NO_DEVELOPMENT) INSTALL(FILES ${RTToolbox_BINARY_DIR}/RTToolboxConfig.cmake ${RTToolbox_BINARY_DIR}/RTToolboxTargets.cmake ${RTToolbox_BINARY_DIR}/RTToolboxLibraryDepends.cmake ${RTToolbox_BINARY_DIR}/UseRTToolbox.cmake DESTINATION ${RTTOOLBOX_INSTALL_PACKAGE_DIR} COMPONENT Development ) ENDIF(NOT RTToolbox_INSTALL_NO_DEVELOPMENT) diff --git a/code/core/rttbDVH.cpp b/code/core/rttbDVH.cpp index f2d8157..fd36886 100644 --- a/code/core/rttbDVH.cpp +++ b/code/core/rttbDVH.cpp @@ -1,418 +1,419 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbDVH.h" #include "rttbException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { DVH::~DVH() {} DVH::DVH(const DataDifferentialType& aDataDifferential, const DoseTypeGy& aDeltaD, const DoseVoxelVolumeType& aDeltaV, IDType aStructureID, IDType aDoseID): _deltaD(aDeltaD), _deltaV(aDeltaV), _structureID(aStructureID), _doseID(aDoseID), _voxelizationID("NONE") { _dataDifferential.clear(); _dataDifferential = aDataDifferential; this->init(); } DVH::DVH(const DataDifferentialType& aDataDifferential, DoseTypeGy aDeltaD, DoseVoxelVolumeType aDeltaV, IDType aStructureID, IDType aDoseID, IDType aVoxelizationID): _deltaD(aDeltaD), _deltaV(aDeltaV), _structureID(aStructureID), _doseID(aDoseID), _voxelizationID(aVoxelizationID) { _dataDifferential.clear(); _dataDifferential = aDataDifferential; this->init(); } DVH::DVH(const DVH& copy) : _structureID(copy._structureID), _doseID(copy._doseID), _voxelizationID(copy._voxelizationID), _label(copy._label) { _deltaD = copy._deltaD; _deltaV = copy._deltaV; _dataDifferential.clear(); _dataDifferential = copy._dataDifferential; this->init(); } DVH& DVH::operator=(const DVH& copy) { if (this != ©) { _deltaD = copy._deltaD; _deltaV = copy._deltaV; _structureID = copy._structureID; _doseID = copy._doseID; _voxelizationID = copy._voxelizationID; _label = copy._label; _dataDifferential.clear(); _dataDifferential = copy._dataDifferential; } this->init(); return *this; } bool operator==(const DVH& aDVH, const DVH& otherDVH) { if (aDVH.getStructureID() != otherDVH.getStructureID()) { return false; } if (aDVH.getDoseID() != otherDVH.getDoseID()) { return false; } if (aDVH.getVoxelizationID() != otherDVH.getVoxelizationID()) { return false; } if (aDVH.getNumberOfVoxels() != otherDVH.getNumberOfVoxels()) { return false; } return true; } std::ostream& operator<<(std::ostream& s, const DVH& aDVH) { s << "[ " << aDVH.getStructureID() << ", " << aDVH.getDoseID() << ", " << aDVH.getVoxelizationID() - << ", " << - aDVH.getNumberOfVoxels() << " ]"; + << "\n " << "Number of Voxels: " << + aDVH.getNumberOfVoxels() << " " << "Minimum/Maximum/Mean/Standard deviation: " << aDVH.getMinimum() << + ", " << aDVH.getMaximum() << ", " << aDVH.getMean() << ", " << aDVH.getStdDeviation() << " ]"; return s; } std::deque DVH::getDataDifferential(bool relativeVolume) const { if (!relativeVolume) { return _dataDifferential; } else { return _dataDifferentialRelative; } } DoseVoxelVolumeType DVH::getDeltaV() const { return _deltaV; } DoseTypeGy DVH::getDeltaD() const { return _deltaD; } IDType DVH::getDoseID() const { return this->_doseID; } IDType DVH::getStructureID() const { return this->_structureID; } IDType DVH::getVoxelizationID() const { return this->_voxelizationID; } void DVH::setDoseID(IDType aDoseID) { _doseID = aDoseID; } void DVH::setStructureID(IDType aStrID) { _structureID = aStrID; } DoseStatisticType DVH::getMaximum() const { return _maximum; } DoseStatisticType DVH::getMinimum() const { return _minimum; } DoseStatisticType DVH::getMean() const { return _mean; } DVHVoxelNumber DVH::getNumberOfVoxels() const { return _numberOfVoxels; } DoseStatisticType DVH::getStdDeviation() const { return _stdDeviation; } DoseStatisticType DVH::getVariance() const { return _variance; } void DVH::init() { if (_deltaD == 0 || _deltaV == 0) { throw InvalidParameterException("DVH init error: neither _deltaD nor _deltaV must be zero!"); } if (this->_dataDifferential.empty()) { throw InvalidParameterException("DVH init error: data differential is empty!"); } double sum = 0; double squareSum = 0; _numberOfVoxels = 0; _maximum = 0; _minimum = 0; _dataCumulative.clear(); this->_dataCumulativeRelative.clear(); this->_dataDifferentialRelative.clear(); DataDifferentialType::iterator it; int i = 0; for (it = _dataDifferential.begin(); it != _dataDifferential.end(); ++it) { _numberOfVoxels += (*it); if ((*it) > 0) { _maximum = (i + 0.5) * this->_deltaD; } if ((_minimum == 0.0f) && ((*it) > 0)) { _minimum = (i + 0.5) * this->_deltaD; } sum += (*it) * (i + 0.5) * this->_deltaD; squareSum += (*it) * pow((i + 0.5) * this->_deltaD, 2); i++; } _mean = sum / _numberOfVoxels; for (it = _dataDifferential.begin(); it != _dataDifferential.end(); ++it) { DoseCalcType datai = ((*it) * 1.0 / _numberOfVoxels); _dataDifferentialRelative.push_back(datai); } _variance = (squareSum / _numberOfVoxels - _mean * _mean); _stdDeviation = pow(_variance, 0.5); _dataCumulative = this->calcCumulativeDVH(); } std::deque DVH::calcCumulativeDVH(bool relativeVolume) { _dataCumulative.clear(); _dataCumulativeRelative.clear(); DoseCalcType cumulativeDVHi = 0; size_t size = _dataDifferential.size(); for (size_t i = 0; i < size; i++) { cumulativeDVHi += _dataDifferential.at(size - i - 1); if (!relativeVolume) { _dataCumulative.push_front(cumulativeDVHi); } else { _dataCumulativeRelative.push_front(cumulativeDVHi / this->getNumberOfVoxels()); } } if (!relativeVolume) { return _dataCumulative; } else { return _dataCumulativeRelative; } } DoseStatisticType DVH::getMedian() const { double median_voxel = 0; int median_i = 0; for (GridIndexType i = 0; i < this->_dataDifferential.size(); i++) { if (median_voxel < (_numberOfVoxels - median_voxel)) { median_voxel += _dataDifferential[i]; median_i = i; } } double median = (median_i + 0.5) * this->_deltaD; return median; } DoseStatisticType DVH::getModal() const { double modal_voxel = 0; int modal_i = 0; for (GridIndexType i = 0; i < this->_dataDifferential.size(); i++) { if (modal_voxel < _dataDifferential[i]) { modal_voxel = _dataDifferential[i]; modal_i = i; } } double modal = (modal_i + 0.5) * this->_deltaD; return modal; } VolumeType DVH::getVx(DoseTypeGy xDoseAbsolute) { GridIndexType i = static_cast(xDoseAbsolute / _deltaD); if (i < _dataCumulative.size()) { VolumeType vx = (_dataCumulative.at(i)); vx = (vx * this->_deltaV); return vx; } else if (i < _dataCumulativeRelative.size()) { VolumeType vx = (_dataCumulativeRelative.at(i)); vx = (vx * this->_deltaV); return vx; } else { return 0; } } DoseTypeGy DVH::getDx(VolumeType xVolumeAbsolute) { GridIndexType i = 0; if (!_dataCumulative.empty()) { for (; i < _dataCumulative.size(); i++) { double volumeAbsoluteI = _dataCumulative[i] * this->_deltaV; if (xVolumeAbsolute > volumeAbsoluteI) { break; } } } else { for (; i < _dataCumulativeRelative.size(); i++) { double volumeAbsoluteI = _dataCumulativeRelative[i] * this->_deltaV; if (xVolumeAbsolute / this->getNumberOfVoxels() > volumeAbsoluteI) { break; } } } if (i <= _dataCumulative.size() && i > 0) { DoseTypeGy dx = (i - 1) * this->_deltaD; return dx; } else if (i < _dataCumulativeRelative.size() && i > 0) { DoseTypeGy dx = (i - 1) * this->_deltaD; return dx; } else { return 0; } } VolumeType DVH::getAbsoluteVolume(int relativePercent) { return (relativePercent * getNumberOfVoxels() * getDeltaV() / 100.0); } void DVH::setLabel(StructureLabel aLabel) { _label = aLabel; } StructureLabel DVH::getLabel() const { return _label; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbDVH.h b/code/core/rttbDVH.h index 671d492..7685034 100644 --- a/code/core/rttbDVH.h +++ b/code/core/rttbDVH.h @@ -1,196 +1,196 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_H #define __DVH_H #include #include #include "rttbBaseType.h" #include "rttbStructure.h" #include "RTTBCoreExports.h" namespace rttb { namespace core { class Structure; /*! @class DVH @brief This is a class representing a dose volume histogram (DVH) */ class RTTBCore_EXPORT DVH { public: typedef std::deque DataDifferentialType; typedef boost::shared_ptr DVHPointer; private: /*! @brief Differential dvh data index is the dose bin, value is the voxel number (sub voxel accuracy) of the dose bin */ DataDifferentialType _dataDifferential; /*! @brief Differential dvh data relative to the total number of voxels */ DataDifferentialType _dataDifferentialRelative; /*! @brief Absolute dose value of a dose-bin in Gy */ DoseTypeGy _deltaD; /*! @brief Volume of a voxel in cm3 */ DoseVoxelVolumeType _deltaV; IDType _structureID; IDType _doseID; IDType _voxelizationID; StructureLabel _label; DoseStatisticType _maximum; DoseStatisticType _minimum; DoseStatisticType _mean; DoseStatisticType _modal; DVHVoxelNumber _numberOfVoxels; DoseStatisticType _median; DoseStatisticType _stdDeviation; DoseStatisticType _variance; DataDifferentialType _dataCumulative; DataDifferentialType _dataCumulativeRelative; - /*! @brief DVH initialisation + /*! @brief DVH initialization The DVH is initialized and all statistical values are calculated. @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ void init(); public: ~DVH(); /*! @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ DVH(const DataDifferentialType& aDataDifferential, const DoseTypeGy& aDeltaD, const DoseVoxelVolumeType& aDeltaV, IDType aStructureID, IDType aDoseID); /*! @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ DVH(const DataDifferentialType& aDataDifferential, DoseTypeGy aDeltaD, DoseVoxelVolumeType aDeltaV, IDType aStructureID, IDType aDoseID, IDType aVoxelizationID); DVH(const DVH& copy); /*! @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ DVH& operator=(const DVH& copy); /*! equality operator DVHs are considered equal if they have the same structure, dose and voxelization ID and the same number of voxels. */ bool friend operator==(const DVH& aDVH, const DVH& otherDVH); friend std::ostream& operator<<(std::ostream& s, const DVH& aDVH); void setLabel(StructureLabel aLabel); StructureLabel getLabel() const; /*! @param relativeVolume default false-> Value is the voxel number of the dose bin; if true-> value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) - @return Return differential data of the dvh (relative or abolute depending on the + @return Return differential data of the dvh (relative or absolute depending on the input parameter). */ DataDifferentialType getDataDifferential(bool relativeVolume = false) const; DoseVoxelVolumeType getDeltaV() const; DoseTypeGy getDeltaD() const; IDType getStructureID() const; IDType getDoseID() const; IDType getVoxelizationID() const; void setDoseID(IDType aDoseID); void setStructureID(IDType aStrID); /*! @brief Calculate number of the voxels (with sub voxel accuracy) @return Return -1 if not initialized */ DVHVoxelNumber getNumberOfVoxels() const; /*! @brief Get the maximum dose in Gy from dvh @return Return the maximum dose in Gy (i+0.5)*deltaD, i-the maximal dose-bin with volume>0 Return -1 if not initialized */ DoseStatisticType getMaximum() const; /*! @brief Get the minimum dose in Gy from dvh @return Return the minimum dose (i+0.5)*deltaD, i-the minimal dose-bin with volume>0 Return -1 if not initialized */ DoseStatisticType getMinimum() const; DoseStatisticType getMean() const; DoseStatisticType getMedian() const; DoseStatisticType getModal() const; DoseStatisticType getStdDeviation() const; DoseStatisticType getVariance() const; /*! @brief Calculate the cumulative data of dvh @param relativeVolume default false-> Value is the voxel number of the dose bin; if true-> value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @return Return cumulative dvh value i-voxel number in dose-bin i */ DataDifferentialType calcCumulativeDVH(bool relativeVolume = false); /*! @brief Get Vx the volume irradiated to >= x @return Return absolute Volume in absolute cm3 Return -1 if not initialized */ VolumeType getVx(DoseTypeGy xDoseAbsolute); /*! @brief Get Dx the minimal dose delivered to x @return Return absolute dose value in Gy Return -1 if not initialized */ DoseTypeGy getDx(VolumeType xVolumeAbsolute); /*! @brief Calculate the absolute volume in cm3 @param relativePercent 0~100, the percent of the whole volume */ VolumeType getAbsoluteVolume(int relativePercent); }; } } #endif diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt index d9b8b6e..8691e7c 100644 --- a/testing/CMakeLists.txt +++ b/testing/CMakeLists.txt @@ -1,92 +1,90 @@ MESSAGE(STATUS "processing RTToolbox testing code") # Testing branch PROJECT(RTTBTesting) #----------------------------------------------------------------------------- # extract and build Litmus #----------------------------------------------------------------------------- include(ExternalProject) message(STATUS "Litmus will be automatically downloaded and built.") set(LITMUS_SOURCE_DIR "${CMAKE_BINARY_DIR}/external/Litmus-src") set(LITMUS_BUILD_DIR "${CMAKE_BINARY_DIR}/external/Litmus-build") set(LITMUS_CMAKE_DIR "${CMAKE_BINARY_DIR}/external/Litmus-cmake") IF ((BUILD_RTToolbox_interpolation_Tester AND BUILD_InterpolationMatchPointTransformation) OR (BUILD_RTToolbox_io_Tester AND BUILD_IO_ITK)) set(ENABLE_ITK "-DLIT_ENABLE_ITK_SUPPORT:BOOL=ON") set(ITK_DIRECTORY "-DITK_DIR:STRING=${ITK_DIR}") ENDIF() #extract and build Litmus ExternalProject_Add( Litmus URL ${RTToolbox_SOURCE_DIR}/utilities/Litmus/Litmus.tar.gz SOURCE_DIR ${LITMUS_SOURCE_DIR} BINARY_DIR ${LITMUS_BUILD_DIR} PREFIX ${LITMUS_CMAKE_DIR} INSTALL_COMMAND "" UPDATE_COMMAND "" # Don't update SVN on every build CMAKE_ARGS -DBUILD_TESTING:BOOL=OFF ${ENABLE_ITK} ${ITK_DIRECTORY} ) #----------------------------------------------------------------------------- # Configure Testing branch #----------------------------------------------------------------------------- MAKE_DIRECTORY(${RTTBTesting_BINARY_DIR}/Temporary) MESSAGE(STATUS "Process All Tests...") #----------------------------------------------------------------------------- # Include sub directories #----------------------------------------------------------------------------- OPTION(BUILD_RTToolbox_core_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_Test_examples "build project on/off" OFF) OPTION(BUILD_RTToolbox_algorithms_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_models_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_io_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_masks_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_interpolation_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_apps_Tester "build project on/off" OFF) +OPTION(BUILD_RTToolbox_validation_Tester "build project on/off" OFF) -IF(${BUILD_RTToolbox_core_Tester} STREQUAL ON) +IF(BUILD_RTToolbox_core_Tester) ADD_SUBDIRECTORY(core) -ENDIF(${BUILD_RTToolbox_core_Tester} STREQUAL ON) +ENDIF() -IF(${BUILD_RTToolbox_Test_examples} STREQUAL ON) +IF(BUILD_RTToolbox_Test_examples) ADD_SUBDIRECTORY(examples) -ENDIF(${BUILD_RTToolbox_Test_examples} STREQUAL ON) +ENDIF() -IF(${BUILD_RTToolbox_algorithms_Tester} STREQUAL ON) +IF(BUILD_RTToolbox_algorithms_Tester) ADD_SUBDIRECTORY(algorithms) -ENDIF(${BUILD_RTToolbox_algorithms_Tester} STREQUAL ON) +ENDIF() -IF(${BUILD_RTToolbox_models_Tester} STREQUAL ON) +IF(BUILD_RTToolbox_models_Tester) ADD_SUBDIRECTORY(models) -ENDIF(${BUILD_RTToolbox_models_Tester} STREQUAL ON) +ENDIF() -IF(${BUILD_RTToolbox_io_Tester} STREQUAL ON) +IF(BUILD_RTToolbox_io_Tester) ADD_SUBDIRECTORY(io) -ENDIF(${BUILD_RTToolbox_io_Tester} STREQUAL ON) +ENDIF() -IF(${BUILD_RTToolbox_masks_Tester} STREQUAL ON) +IF(BUILD_RTToolbox_masks_Tester) ADD_SUBDIRECTORY(masks) -ENDIF(${BUILD_RTToolbox_masks_Tester} STREQUAL ON) +ENDIF() -IF(${BUILD_RTToolbox_interpolation_Tester} STREQUAL ON) +IF(BUILD_RTToolbox_interpolation_Tester) ADD_SUBDIRECTORY(interpolation) -ENDIF(${BUILD_RTToolbox_interpolation_Tester} STREQUAL ON) - -IF(${BUILD_RTToolbox_apps_Tester} STREQUAL ON) - ADD_SUBDIRECTORY(apps) -ENDIF(${BUILD_RTToolbox_apps_Tester} STREQUAL ON) - - - - - +ENDIF() +IF(BUILD_RTToolbox_validation_Tester) + ADD_SUBDIRECTORY(validation) +ENDIF() +IF(BUILD_RTToolbox_apps_Tester) + ADD_SUBDIRECTORY(apps) +ENDIF() diff --git a/testing/examples/CMakeLists.txt b/testing/examples/CMakeLists.txt index 28bacaa..13bd3b8 100644 --- a/testing/examples/CMakeLists.txt +++ b/testing/examples/CMakeLists.txt @@ -1,49 +1,39 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(CORE_TEST_EXAMPLES ${EXECUTABLE_OUTPUT_PATH}/rttbExamplesTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/Temporary) #----------------------------------------------------------------------------- ADD_TEST(RTBioModelExampleTest ${CORE_TEST_EXAMPLES} RTBioModelExampleTest "${TEST_DATA_ROOT}/DVH/Text/dvh_PTV_HIT.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_test_HT1.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_test_HT2.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_test_HT3.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_test_TV.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_virtuos_diff_trunk6.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_virtuos_diff_trunk8.txt") -ADD_TEST(DVHCalculatorExampleTest ${CORE_TEST_EXAMPLES} DVHCalculatorExampleTest -"${TEST_DATA_ROOT}/StructureSet/DICOM/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/Dose/DICOM/ConstantTwoGridScaling.dcm" -"${TEST_DATA_ROOT}/Dose/DICOM/ConstantTwoGridScaling05.dcm" "${TEST_DATA_ROOT}/Dose/DICOM/ConstantFiftyGridScaling01.dcm") ADD_TEST(RTDoseIndexTest ${CORE_TEST_EXAMPLES} RTDoseIndexTest "${TEST_DATA_ROOT}/DVH/Text/dvh_test_TV.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_test_HT1.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_test_HT2.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_test_HT3.txt") ADD_TEST(RTDoseStatisticsDicomTest ${CORE_TEST_EXAMPLES} RTDoseStatisticsDicomTest "${TEST_DATA_ROOT}/Dose/DICOM/ConstantTwo_withDoseGridScaling.dcm") IF(RTTB_VIRTUOS_SUPPORT AND BUILD_IO_Virtuos) ADD_TEST(RTDoseStatisticsVirtuosTest ${CORE_TEST_EXAMPLES} RTDoseStatisticsVirtuosTest "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.vdx" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.pln") ENDIF() ADD_TEST(RTDVHTest ${CORE_TEST_EXAMPLES} RTDVHTest "${TEST_DATA_ROOT}/DVH/Text/dvh_test.txt") -ADD_TEST(DVHCalculatorExampleTest ${CORE_TEST_EXAMPLES} DVHCalculatorExampleTest -"${TEST_DATA_ROOT}/StructureSet/DICOM/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/Dose/DICOM/ConstantTwo_withDoseGridScaling.dcm" -"${TEST_DATA_ROOT}/Dose/DICOM/LinearIncrease3D.dcm" "${TEST_DATA_ROOT}/Dose/DICOM/LinearIncreaseX.dcm") ADD_TEST(RTBioModelScatterPlotExampleTest ${CORE_TEST_EXAMPLES} RTBioModelScatterPlotExampleTest "${TEST_DATA_ROOT}/DVH/Text/dvh_PTV_HIT.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_test_HT1.txt" "${TEST_DATA_ROOT}/DVH/Text/dvh_test_TV.txt") -ADD_TEST(VoxelizationValidationTest ${CORE_TEST_EXAMPLES} VoxelizationValidationTest -"${TEST_DATA_ROOT}/StructureSet/DICOM/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" -"${TEST_DATA_ROOT}/Dose/DICOM/LinearIncrease3D.dcm" "${TEST_DATA_ROOT}/Mask/BoostMask/" "${TEST_DATA_ROOT}/Mask/OTBMask/" "${TEST_DATA_ROOT}/Mask/BoostMaskRedesign/" -"${TEST_DATA_ROOT}/Dose/DICOM/PatBM116__RTDOSE_Main_corr.mhd" "${TEST_DATA_ROOT}/StructureSet/DICOM/__1__mm__1.2.276.0.28.19.640188827224102750711261838091512821903075578763.4195312189") IF(RTTB_VIRTUOS_SUPPORT AND BUILD_IO_Virtuos) - RTTB_CREATE_TEST_MODULE(rttbExamples DEPENDS RTTBCore RTTBAlgorithms RTTBMasks RTTBOTBMask RTTBBoostMask RTTBIndices RTTBDicomIO RTTBVirtuosIO RTTBITKIO RTTBOtherIO RTTBModels PACKAGE_DEPENDS Litmus) + RTTB_CREATE_TEST_MODULE(rttbExamples DEPENDS RTTBCore RTTBAlgorithms RTTBMasks RTTBBoostMask RTTBIndices RTTBDicomIO RTTBVirtuosIO RTTBITKIO RTTBOtherIO RTTBModels PACKAGE_DEPENDS Litmus) ELSE() - RTTB_CREATE_TEST_MODULE(rttbExamples DEPENDS RTTBCore RTTBAlgorithms RTTBMasks RTTBOTBMask RTTBBoostMask RTTBIndices RTTBDicomIO RTTBITKIO RTTBOtherIO RTTBModels PACKAGE_DEPENDS Litmus) + RTTB_CREATE_TEST_MODULE(rttbExamples DEPENDS RTTBCore RTTBAlgorithms RTTBMasks RTTBBoostMask RTTBIndices RTTBDicomIO RTTBITKIO RTTBOtherIO RTTBModels PACKAGE_DEPENDS Litmus) ENDIF() diff --git a/testing/examples/DVHCalculatorComparisonTest.cpp b/testing/examples/DVHCalculatorComparisonTest.cpp deleted file mode 100644 index 3c7c539..0000000 --- a/testing/examples/DVHCalculatorComparisonTest.cpp +++ /dev/null @@ -1,365 +0,0 @@ -// ----------------------------------------------------------------------- -// RTToolbox - DKFZ radiotherapy quantitative evaluation library -// -// Copyright (c) German Cancer Research Center (DKFZ), -// Software development for Integrated Diagnostics and Therapy (SIDT). -// ALL RIGHTS RESERVED. -// See rttbCopyright.txt or -// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notices for more information. -// -//------------------------------------------------------------------------ -/*! -// @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - -// this file defines the rttbCoreTests for the test driver -// and all it expects is that you have a function called RegisterTests - -#include -#include - -#include - -#include "litCheckMacros.h" - -#include "rttbBaseType.h" -#include "rttbDVHCalculator.h" -#include "rttbGenericMaskedDoseIterator.h" -#include "rttbGenericDoseIterator.h" -#include "rttbNullPointerException.h" -#include "rttbInvalidParameterException.h" -#include "rttbDicomDoseAccessor.h" -#include "rttbDicomFileDoseAccessorGenerator.h" -#include "rttbDicomFileStructureSetGenerator.h" -#include "rttbOTBMaskAccessor.h" -#include "rttbDVHTxtFileReader.h" - - -namespace rttb -{ - - namespace testing - { - - /*! @brief DVHCalculatorTest. - Test if calculation in new architecture returns similar results to the - original implementation. - - WARNING: The values for comparison need to be adjusted if the input files are changed! - - This test can be used to get more detailed information, but it will always fail, because differences in voxelization accuracy, - especially the ones caused by the change from double to float precission will not cause considerable deviations in the structure - sizes, which correspond to considerable differences in the calculated DVHs. - - Even in double precission differences up to 0.005 between values from old and new implementation can occure. - */ - - int DVHCalculatorComparisonTest(int argc, char* argv[]) - { - typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; - typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; - typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; - typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; - - PREPARE_DEFAULT_TEST_REPORTING; - //ARGUMENTS: 1: structure file name - // 2: dose1 file name - // 3: dose2 file name - // 4: dose3 file name - - std::string RTSTRUCT_FILENAME; - std::string RTDOSE_FILENAME; - std::string RTDOSE2_FILENAME; - std::string RTDOSE3_FILENAME; - std::string COMPARISON_DVH_FOLDER; - - - if (argc > 1) - { - RTSTRUCT_FILENAME = argv[1]; - } - - if (argc > 2) - { - RTDOSE_FILENAME = argv[2]; - } - - if (argc > 3) - { - RTDOSE2_FILENAME = argv[3]; - } - - if (argc > 4) - { - RTDOSE3_FILENAME = argv[4]; - } - - if (argc > 5) - { - COMPARISON_DVH_FOLDER = argv[5]; - } - - - OFCondition status; - DcmFileFormat fileformat; - - /* read dicom-rt dose */ - io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); - DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); - - //create a vector of MaskAccessors (one for each structure) - StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( - RTSTRUCT_FILENAME.c_str()).generateStructureSet(); - - std::vector rtStructSetMaskAccessorVec; - - ::DRTDoseIOD rtdose2; - io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2(RTDOSE2_FILENAME.c_str()); - DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); - - - ::DRTDoseIOD rtdose3; - io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator3(RTDOSE3_FILENAME.c_str()); - DoseAccessorPointer doseAccessor3(doseAccessorGenerator3.generateDoseAccessor()); - - - double maxDifference = 0; - double difference = 0; - double minDifference = 1000; - clock_t start(clock()); - - if (rtStructureSet->getNumberOfStructures() > 0) - { - for (int j = 0; j < static_cast(rtStructureSet->getNumberOfStructures()); j++) - { - - //create MaskAccessor - ::boost::shared_ptr spOTBMaskAccessor = - ::boost::make_shared(rtStructureSet->getStructure(j), - doseAccessor1->getGeometricInfo()); - spOTBMaskAccessor->updateMask(); - MaskAccessorPointer spMaskAccessor(spOTBMaskAccessor); - //create corresponding MaskedDoseIterator - ::boost::shared_ptr spMaskedDoseIteratorTmp = - ::boost::make_shared(spMaskAccessor, doseAccessor1); - DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); - //store MaskAccessor - rtStructSetMaskAccessorVec.push_back(spMaskAccessor); - - rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), - doseAccessor1->getUID()); - std::string dvhFileName = "dvh1"; - std::string label = (rtStructureSet->getStructure(j))->getLabel(); - dvhFileName.append(label); - - if (dvhFileName.find("/") != std::string::npos) - { - dvhFileName.replace(dvhFileName.find("/"), 1, ""); - } - - std::cout << "=== Dose 1: " << label << "===" << std::endl; - rttb::io::other::DVHTxtFileReader dvhOriginalReader = rttb::io::other::DVHTxtFileReader( - COMPARISON_DVH_FOLDER + dvhFileName + ".txt"); - rttb::core::DVH dvhOrig = *(dvhOriginalReader.generateDVH()); - rttb::core::DVH::DataDifferentialType dvhOrigData = dvhOrig.getDataDifferential(); - - rttb::core::DVH dvh = *(calc.generateDVH()); - rttb::core::DVH::DataDifferentialType dvhData = dvh.getDataDifferential(); - - CHECK_EQUAL(dvhOrig, dvh); - CHECK_CLOSE(dvhOrig.getMaximum(), dvh.getMaximum(), errorConstant); - CHECK_CLOSE(dvhOrig.getMinimum(), dvh.getMinimum(), errorConstant); - CHECK_CLOSE(dvhOrig.getMean(), dvh.getMean(), errorConstant); - - rttb::core::DVH::DataDifferentialType::iterator it; - rttb::core::DVH::DataDifferentialType::iterator itOrig; - itOrig = dvhOrigData.begin(); - - for (it = dvhData.begin(); it != dvhData.end() || itOrig != dvhOrigData.end(); ++it, ++itOrig) - { - CHECK_CLOSE(*(itOrig), *(it), errorConstant); - std::cout << std::setprecision(20) << "difference: " << abs(*(itOrig) - * (it)) << std::endl; - difference = abs(*(itOrig) - * (it)); - - if (difference < minDifference) - { - minDifference = difference; - } - - if (difference > maxDifference) - { - maxDifference = difference; - } - } - } - } - - clock_t finish(clock()); - std::cout << std::setprecision(20) << "max(difference): " << maxDifference << std::endl; - std::cout << std::setprecision(20) << "min(difference): " << minDifference << std::endl; - - std::cout << "DVH Calculation time: " << finish - start << " ms" << std::endl; - - maxDifference = 0; - minDifference = 1000; - - clock_t start2(clock()); - - for (size_t j = 0; j < rtStructSetMaskAccessorVec.size(); j++) - { - //create corresponding MaskedDoseIterator - ::boost::shared_ptr spMaskedDoseIteratorTmp = - ::boost::make_shared(rtStructSetMaskAccessorVec.at(j), - doseAccessor2); - DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); - - rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), - doseAccessor2->getUID()); - std::string dvhFileName = "dvh2"; - std::string label = (rtStructureSet->getStructure(j))->getLabel(); - dvhFileName.append(label); - - if (dvhFileName.find("/") != std::string::npos) - { - dvhFileName.replace(dvhFileName.find("/"), 1, ""); - } - - std::cout << "=== Dose 2: " << label << "===" << std::endl; - rttb::io::other::DVHTxtFileReader dvhOriginalReader = rttb::io::other::DVHTxtFileReader( - COMPARISON_DVH_FOLDER + dvhFileName + ".txt"); - rttb::core::DVH dvhOrig = *(dvhOriginalReader.generateDVH()); - rttb::core::DVH::DataDifferentialType dvhOrigData = dvhOrig.getDataDifferential(); - - rttb::core::DVH dvh = *(calc.generateDVH()); - rttb::core::DVH::DataDifferentialType dvhData = dvh.getDataDifferential(); - - CHECK_EQUAL(dvhOrig, dvh); - CHECK_CLOSE(dvhOrig.getMaximum(), dvh.getMaximum(), errorConstant); - CHECK_CLOSE(dvhOrig.getMinimum(), dvh.getMinimum(), errorConstant); - CHECK_CLOSE(dvhOrig.getMean(), dvh.getMean(), errorConstant); - - rttb::core::DVH::DataDifferentialType::iterator it; - rttb::core::DVH::DataDifferentialType::iterator itOrig; - itOrig = dvhOrigData.begin(); - - for (it = dvhData.begin(); it != dvhData.end() || itOrig != dvhOrigData.end(); ++it, ++itOrig) - { - CHECK_CLOSE(*(itOrig), *(it), errorConstant); - std::cout << std::setprecision(20) << "difference: " << abs(*(itOrig) - * (it)) << std::endl; - difference = abs(*(itOrig) - * (it)); - - if (difference > 10) - { - std::cout << "large difference: " << abs(*(itOrig) - * (it)) << " = " << *(itOrig) << " - " << * - (it) << std::endl; - } - - if (difference < minDifference) - { - minDifference = difference; - } - - if (difference > maxDifference) - { - maxDifference = difference; - } - } - } - - clock_t finish2(clock()); - - std::cout << std::setprecision(20) << "max(difference): " << maxDifference << std::endl; - std::cout << std::setprecision(20) << "min(difference): " << minDifference << std::endl; - - std::cout << "Reset dose 2, DVH Calculation time: " << finish2 - start2 << " ms" << std::endl; - - maxDifference = 0; - minDifference = 1000; - - clock_t start3(clock()); - - for (size_t j = 0; j < rtStructSetMaskAccessorVec.size(); j++) - { - //create corresponding MaskedDoseIterator - ::boost::shared_ptr spMaskedDoseIteratorTmp = - ::boost::make_shared(rtStructSetMaskAccessorVec.at(j), - doseAccessor3); - DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); - - rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), - doseAccessor3->getUID()); - std::string dvhFileName = "dvh3"; - std::string label = (rtStructureSet->getStructure(j))->getLabel(); - dvhFileName.append(label); - - if (dvhFileName.find("/") != std::string::npos) - { - dvhFileName.replace(dvhFileName.find("/"), 1, ""); - } - - std::cout << "=== Dose 3: " << label << "===" << std::endl; - rttb::io::other::DVHTxtFileReader dvhOriginalReader = rttb::io::other::DVHTxtFileReader( - COMPARISON_DVH_FOLDER + dvhFileName + ".txt"); - rttb::core::DVH dvhOrig = *(dvhOriginalReader.generateDVH()); - rttb::core::DVH::DataDifferentialType dvhOrigData = dvhOrig.getDataDifferential(); - - rttb::core::DVH dvh = *(calc.generateDVH()); - rttb::core::DVH::DataDifferentialType dvhData = dvh.getDataDifferential(); - - CHECK_EQUAL(dvhOrig, dvh); - CHECK_CLOSE(dvhOrig.getMaximum(), dvh.getMaximum(), errorConstant); - CHECK_CLOSE(dvhOrig.getMinimum(), dvh.getMinimum(), errorConstant); - CHECK_CLOSE(dvhOrig.getMean(), dvh.getMean(), errorConstant); - - rttb::core::DVH::DataDifferentialType::iterator it; - rttb::core::DVH::DataDifferentialType::iterator itOrig; - itOrig = dvhOrigData.begin(); - - for (it = dvhData.begin(); it != dvhData.end() || itOrig != dvhOrigData.end(); ++it, ++itOrig) - { - CHECK_CLOSE(*(itOrig), *(it), errorConstant); - std::cout << std::setprecision(20) << "difference: " << abs(*(itOrig) - * (it)) << std::endl; - - if (difference > 10) - { - std::cout << "large difference: " << abs(*(itOrig) - * (it)) << " = " << *(itOrig) << " - " << * - (it) << std::endl; - } - - difference = abs(*(itOrig) - * (it)); - - if (difference < minDifference) - { - minDifference = difference; - } - - if (difference > maxDifference) - { - maxDifference = difference; - } - } - } - - clock_t finish3(clock()); - - std::cout << std::setprecision(20) << "max(difference): " << maxDifference << std::endl; - std::cout << std::setprecision(20) << "min(difference): " << minDifference << std::endl; - - std::cout << "Reset dose 3, DVH Calculation time: " << finish3 - start3 << " ms" << std::endl; - - - RETURN_AND_REPORT_TEST_SUCCESS; - - - } - - }//testing -}//rttb - diff --git a/testing/examples/DVHCalculatorExampleTest.cpp b/testing/examples/DVHCalculatorExampleTest.cpp deleted file mode 100644 index 89ce459..0000000 --- a/testing/examples/DVHCalculatorExampleTest.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// ----------------------------------------------------------------------- -// RTToolbox - DKFZ radiotherapy quantitative evaluation library -// -// Copyright (c) German Cancer Research Center (DKFZ), -// Software development for Integrated Diagnostics and Therapy (SIDT). -// ALL RIGHTS RESERVED. -// See rttbCopyright.txt or -// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notices for more information. -// -//------------------------------------------------------------------------ -/*! -// @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - -// this file defines the rttbCoreTests for the test driver -// and all it expects is that you have a function called RegisterTests - -#include -#include - -#include - -#include "litCheckMacros.h" - -#include "rttbBaseType.h" -#include "rttbDVHCalculator.h" -#include "rttbGenericMaskedDoseIterator.h" -#include "rttbGenericDoseIterator.h" -#include "rttbNullPointerException.h" -#include "rttbInvalidParameterException.h" -#include "rttbDicomDoseAccessor.h" -#include "rttbDicomFileDoseAccessorGenerator.h" -#include "rttbDicomFileStructureSetGenerator.h" -#include "rttbOTBMaskAccessor.h" - - -namespace rttb -{ - - namespace testing - { - - /*! @brief DVHCalculatorTest. - Test if calculation in new architecture returns similar results to the - original implementation. - - WARNING: The values for comparison need to be adjusted if the input files are changed! - */ - - int DVHCalculatorExampleTest(int argc, char* argv[]) - { - typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; - typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; - typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; - typedef core::DVHCalculator::MaskedDoseIteratorPointer MaskedDoseIteratorPointer; - typedef masks::legacy::OTBMaskAccessor::StructTypePointer StructTypePointer; - typedef core::DVH::DVHPointer DVHPointer; - typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; - - PREPARE_DEFAULT_TEST_REPORTING; - //ARGUMENTS: 1: structure file name - // 2: dose1 file name - // 3: dose2 file name - // 4: dose3 file name - - std::string RTSTRUCT_FILENAME; - std::string RTDOSE_FILENAME; - std::string RTDOSE2_FILENAME; - std::string RTDOSE3_FILENAME; - - - if (argc > 1) - { - RTSTRUCT_FILENAME = argv[1]; - } - - if (argc > 2) - { - RTDOSE_FILENAME = argv[2]; - } - - if (argc > 3) - { - RTDOSE2_FILENAME = argv[3]; - } - - if (argc > 4) - { - RTDOSE3_FILENAME = argv[4]; - } - - OFCondition status; - DcmFileFormat fileformat; - - // read dicom-rt dose - io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); - - DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); - - //create a vector of MaskAccessors (one for each structure) - StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( - RTSTRUCT_FILENAME.c_str()).generateStructureSet(); - - //storeage for mask accessors to reduce time spent on voxelization (perform only once) - std::vector rtStructSetMaskAccessorVec; - - ::DRTDoseIOD rtdose2; - io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2(RTDOSE2_FILENAME.c_str()); - DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); - - - ::DRTDoseIOD rtdose3; - io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator3(RTDOSE3_FILENAME.c_str()); - DoseAccessorPointer doseAccessor3(doseAccessorGenerator3.generateDoseAccessor()); - - //start evaluation - clock_t start(clock()); - - if (rtStructureSet->getNumberOfStructures() > 0) - { - for (int j = 0; j < static_cast(rtStructureSet->getNumberOfStructures()); j++) - { - std::cout << rtStructureSet->getStructure(j)->getLabel() << std::endl; - - //create MaskAccessor for each structure - ::boost::shared_ptr spOTBMaskAccessor = - ::boost::make_shared(rtStructureSet->getStructure(j), - doseAccessor1->getGeometricInfo()); - spOTBMaskAccessor->updateMask(); - MaskAccessorPointer spMaskAccessor(spOTBMaskAccessor); - - //create corresponding MaskedDoseIterator - ::boost::shared_ptr spMaskedDoseIteratorTmp = - ::boost::make_shared(spMaskAccessor, doseAccessor1); - DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); - //store MaskAccessor for each structure (later reuse) - rtStructSetMaskAccessorVec.push_back(spMaskAccessor); - - //calculate DVH - rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), - doseAccessor1->getUID()); - rttb::core::DVH dvh = *(calc.generateDVH()); - - - //DEBUG OUTPUT - std::cout << "=== Dose 1 Structure " << j << "===" << std::endl; - std::cout << std::setprecision(20) << "max: " << dvh.getMaximum() << std::endl; - std::cout << std::setprecision(20) << "min: " << dvh.getMinimum() << std::endl; - std::cout << std::setprecision(20) << "mean: " << dvh.getMean() << std::endl; - std::cout << std::setprecision(20) << "median: " << dvh.getMedian() << std::endl; - std::cout << std::setprecision(20) << "modal: " << dvh.getModal() << std::endl; - std::cout << std::setprecision(20) << "std: " << dvh.getStdDeviation() << std::endl; - std::cout << std::setprecision(20) << "var: " << dvh.getVariance() << std::endl; - std::cout << std::setprecision(20) << "numV: " << dvh.getNumberOfVoxels() << std::endl; - - - //compare explicit values for some results. - //expected values were generated from the original implementation - if (j == 0) - { - CHECK_CLOSE(5.6658345820895519e-005, dvh.getMaximum(), 1e-3); - CHECK_CLOSE(5.6658345820895519e-005, dvh.getMinimum(), errorConstant); - CHECK_CLOSE(5.6658345820895525e-005, dvh.getMean(), errorConstant); - CHECK_CLOSE(5.6658345820895519e-005, dvh.getMedian(), errorConstant); - CHECK_CLOSE(5.6658345820895519e-005, dvh.getModal(), errorConstant); - CHECK_CLOSE(-4.1359030627651384e-025, dvh.getVariance(), errorConstant); - CHECK_CLOSE(89230.858052685173, dvh.getNumberOfVoxels(), 2e-1); - } - - if (j == 1) - { - CHECK_CLOSE(-1.2407709188295415e-024, dvh.getVariance(), errorConstant); - CHECK_CLOSE(595.30645355716683, dvh.getNumberOfVoxels(), 1e-3); - } - - if (j == 2) - { - CHECK_CLOSE(-4.1359030627651384e-025, dvh.getVariance(), errorConstant); - CHECK_CLOSE(1269.9125811291087, dvh.getNumberOfVoxels(), 1e-3); - } - - if (j == 9) - { - CHECK_CLOSE(5.6658345820895519e-005, dvh.getMaximum(), 1e-3); - CHECK_CLOSE(5.6658345820895519e-005, dvh.getMinimum(), errorConstant); - CHECK_CLOSE(5.6658345820895519e-005, dvh.getMean(), errorConstant); - CHECK_CLOSE(5.6658345820895519e-005, dvh.getMedian(), errorConstant); - CHECK_CLOSE(5.6658345820895519e-005, dvh.getModal(), errorConstant); - CHECK_CLOSE(0, dvh.getStdDeviation(), errorConstant); - CHECK_CLOSE(0, dvh.getVariance(), errorConstant); - CHECK_CLOSE(1328.4918116279605, dvh.getNumberOfVoxels(), 1e-3); - } - - } - } - - clock_t finish(clock()); - - std::cout << "DVH Calculation time: " << finish - start << " ms" << std::endl; - - clock_t start2(clock()); - - for (size_t j = 0; j < rtStructSetMaskAccessorVec.size(); j++) - { - //create corresponding MaskedDoseIterator - ::boost::shared_ptr spMaskedDoseIteratorTmp = - ::boost::make_shared(rtStructSetMaskAccessorVec.at(j), - doseAccessor2); - DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); - - //calculate DVH - rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), - doseAccessor2->getUID()); - rttb::core::DVH dvh = *(calc.generateDVH()); - - - if (j == 0) - { - CHECK_CLOSE(1.8423272053074631, dvh.getMaximum(), 1e-1); - CHECK_CLOSE(0.0069001018925373145, dvh.getMinimum(), errorConstant); - CHECK_CLOSE(0.5534586388640208, dvh.getMean(), errorConstant); - CHECK_CLOSE(0.42090621544477619, dvh.getMedian(), errorConstant); - CHECK_CLOSE(0.075901120817910464, dvh.getModal(), errorConstant); - CHECK_CLOSE(0.44688344565881616, dvh.getStdDeviation(), 1e-4); - CHECK_CLOSE(0.19970481400389611, dvh.getVariance(), 1e-4); - CHECK_CLOSE(89230.858052685187, dvh.getNumberOfVoxels(), 1e-1); - } - - if (j == 4) - { - CHECK_CLOSE(1.6264736515373135, dvh.getMaximum(), 1e-3); - CHECK_CLOSE(0.10433981915522389, dvh.getMinimum(), errorConstant); - CHECK_CLOSE(0.70820073085773427, dvh.getMean(), errorConstant); - CHECK_CLOSE(0.71810346124477609, dvh.getMedian(), errorConstant); - CHECK_CLOSE(0.23936782041492538, dvh.getModal(), errorConstant); - CHECK_CLOSE(0.36355099006842068, dvh.getStdDeviation(), errorConstant); - CHECK_CLOSE(0.13216932237972889, dvh.getVariance(), errorConstant); - CHECK_CLOSE(2299.7105030728999, dvh.getNumberOfVoxels(), 1e-3); - } - } - - clock_t finish2(clock()); - - std::cout << "Reset dose 2, DVH Calculation time: " << finish2 - start2 << " ms" << std::endl; - - clock_t start3(clock()); - - for (size_t j = 0; j < rtStructSetMaskAccessorVec.size(); j++) - { - //create corresponding MaskedDoseIterator - ::boost::shared_ptr spMaskedDoseIteratorTmp = - ::boost::make_shared(rtStructSetMaskAccessorVec.at(j), - doseAccessor3); - DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); - - //calculate DVH - rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), - doseAccessor3->getUID()); - rttb::core::DVH dvh = *(calc.generateDVH()); - - - if (j == 1) - { - CHECK_CLOSE(0.0010765085705970151, dvh.getMaximum(), 1e-3); - CHECK_CLOSE(0.00087641404074626872, dvh.getMinimum(), errorConstant); - CHECK_CLOSE(0.0009788401527774486, dvh.getMean(), errorConstant); - CHECK_CLOSE(0.00098846697746268666, dvh.getMedian(), errorConstant); - CHECK_CLOSE(0.00098846697746268666, dvh.getModal(), errorConstant); - CHECK_CLOSE(3.2977969280849566e-005, dvh.getStdDeviation(), errorConstant); - CHECK_CLOSE(1.0875464578886574e-009, dvh.getVariance(), errorConstant); - CHECK_CLOSE(595.30645355716683, dvh.getNumberOfVoxels(), 1e-3); - } - - if (j == 6) - { - CHECK_CLOSE(0.0016589942782835824, dvh.getMaximum(), 1e-3); - CHECK_CLOSE(0.00027960577723880602, dvh.getMinimum(), errorConstant); - CHECK_CLOSE(0.0010389077643351956, dvh.getMean(), errorConstant); - CHECK_CLOSE(0.0011246365706716419, dvh.getMedian(), errorConstant); - CHECK_CLOSE(0.0013856019627611941, dvh.getModal(), errorConstant); - CHECK_CLOSE(0.00036431958148461669, dvh.getStdDeviation(), errorConstant); - CHECK_CLOSE(1.3272875745312625e-007, dvh.getVariance(), errorConstant); - CHECK_CLOSE(8034.8878045085003, dvh.getNumberOfVoxels(), 1e-2); - } - } - - clock_t finish3(clock()); - - std::cout << "Reset dose 3, DVH Calculation time: " << finish3 - start3 << " ms" << std::endl; - - - - RETURN_AND_REPORT_TEST_SUCCESS; - } - - }//testing -}//rttb - diff --git a/testing/examples/RTDoseStatisticsVirtuosTest.cpp b/testing/examples/RTDoseStatisticsVirtuosTest.cpp index 81b29be..33a26f3 100644 --- a/testing/examples/RTDoseStatisticsVirtuosTest.cpp +++ b/testing/examples/RTDoseStatisticsVirtuosTest.cpp @@ -1,138 +1,138 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 1328 $ (last changed revision) // @date $Date: 2016-04-22 09:50:01 +0200 (Fr, 22 Apr 2016) $ (last change date) // @author $Author: hentsch $ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "rttbDoseStatistics.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" #include "rttbVirtuosFileStructureSetGenerator.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbBaseType.h" namespace rttb { namespace testing { /*! @brief RTDoseStatisticsTest. Max, min, mean, standard deviation, variance, Vx, Dx, MOHx, MOCx, MaxOHx, MinOCx are tested. Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed!*/ int RTDoseStatisticsVirtuosTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME; std::string RTSTRUCT_FILENAME; std::string RTPLAN_FILENAME; if (argc > 3) { RTDOSE_FILENAME = argv[1]; RTSTRUCT_FILENAME = argv[2]; RTPLAN_FILENAME = argv[3]; } else { std::cout << "at least three arguments required for RTDoseStatisticsVirtuosTest" << std::endl; return -1; } //Structure 2 is RUECKENMARK typedef core::GenericDoseIterator::DoseIteratorPointer DoseIteratorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef rttb::algorithms::DoseStatistics::DoseStatisticsPointer DoseStatisticsPointer; typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; typedef algorithms::DoseStatisticsCalculator::ResultListPointer ResultListPointer; DoseAccessorPointer virtuosDoseAccessor = io::virtuos::VirtuosPlanFileDoseAccessorGenerator( RTDOSE_FILENAME.c_str(), RTPLAN_FILENAME.c_str()).generateDoseAccessor(); StructureSetPointer virtuosStructureSet = io::virtuos::VirtuosFileStructureSetGenerator( RTSTRUCT_FILENAME.c_str(), RTDOSE_FILENAME.c_str()).generateStructureSet(); - boost::shared_ptr spOTBMaskAccessorVirtuos = + boost::shared_ptr spMaskAccessorVirtuos = boost::make_shared(virtuosStructureSet->getStructure(2), virtuosDoseAccessor->getGeometricInfo()); - spOTBMaskAccessorVirtuos->updateMask(); + spMaskAccessorVirtuos->updateMask(); - MaskAccessorPointer spMaskAccessor(spOTBMaskAccessorVirtuos); + MaskAccessorPointer spMaskAccessor(spMaskAccessorVirtuos); //create corresponding MaskedDoseIterator boost::shared_ptr spMaskedDoseIteratorTmp = boost::make_shared(spMaskAccessor, virtuosDoseAccessor); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); rttb::algorithms::DoseStatisticsCalculator doseStatisticsCalculatorVirtuos(spMaskedDoseIterator); DoseStatisticsPointer doseStatisticsVirtuos = doseStatisticsCalculatorVirtuos.calculateDoseStatistics(true); //comparison values computed with "old" DoseStatistics implementation CHECK_CLOSE(doseStatisticsVirtuos->getMinimum(), 6.4089, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMaximum(), 39.0734, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMean(), 22.5779, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getStdDeviation(), 6.28857, reducedErrorConstant); ResultListPointer maxPositions = doseStatisticsVirtuos->getMaximumVoxelPositions(); ResultListPointer minPositions = doseStatisticsVirtuos->getMinimumVoxelPositions(); CHECK_EQUAL(maxPositions->size(), 1); CHECK_EQUAL(minPositions->size(), 1); CHECK_EQUAL(maxPositions->begin()->first, doseStatisticsVirtuos->getMaximum()); CHECK_EQUAL(maxPositions->begin()->second, 3570772); CHECK_EQUAL(minPositions->begin()->first, doseStatisticsVirtuos->getMinimum()); CHECK_EQUAL(minPositions->begin()->second, 3571264); CHECK_CLOSE(doseStatisticsVirtuos->getDx(0.02 * doseStatisticsVirtuos->getVolume()), 31.8358, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getVx(0.9 * doseStatisticsVirtuos->getMaximum()), 0.471747, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMOHx(0.1 * doseStatisticsVirtuos->getVolume()), 31.3266, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMOCx(0.05 * doseStatisticsVirtuos->getVolume()), 9.01261, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMaxOHx(0.95 * doseStatisticsVirtuos->getVolume()), 10.3764, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMinOCx(0.98 * doseStatisticsVirtuos->getVolume()), 31.8373, reducedErrorConstant); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/examples/files.cmake b/testing/examples/files.cmake index afb95f3..3cfc88c 100644 --- a/testing/examples/files.cmake +++ b/testing/examples/files.cmake @@ -1,23 +1,19 @@ SET(DOSESTATISTICSVIRTUOSTEST "") IF(RTTB_VIRTUOS_SUPPORT AND BUILD_IO_Virtuos) SET(DOSESTATISTICSVIRTUOSTEST "RTDoseStatisticsVirtuosTest.cpp") ENDIF() SET(CPP_FILES RTBioModelExampleTest.cpp RTBioModelScatterPlotExampleTest.cpp RTDoseIndexTest.cpp RTDoseStatisticsDicomTest.cpp ${DOSESTATISTICSVIRTUOSTEST} RTDVHTest.cpp - DVHCalculatorExampleTest.cpp - DVHCalculatorComparisonTest.cpp ../models/rttbScatterTester.cpp rttbTestExamples.cpp - VoxelizationValidationTest.cpp ) SET(H_FILES ../models/rttbScatterTester.h - ) diff --git a/testing/examples/rttbTestExamples.cpp b/testing/examples/rttbTestExamples.cpp index 6595247..0bd7b87 100644 --- a/testing/examples/rttbTestExamples.cpp +++ b/testing/examples/rttbTestExamples.cpp @@ -1,76 +1,74 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "litMultiTestsMain.h" #include "RTToolboxConfigure.h" namespace rttb { namespace testing { void registerTests() { LIT_REGISTER_TEST(RTBioModelExampleTest); - LIT_REGISTER_TEST(DVHCalculatorExampleTest); LIT_REGISTER_TEST(RTDVHTest); LIT_REGISTER_TEST(RTDoseIndexTest); if (RTTB_VIRTUOS_SUPPORT) { LIT_REGISTER_TEST(RTDoseStatisticsVirtuosTest); } LIT_REGISTER_TEST(RTDoseStatisticsDicomTest); LIT_REGISTER_TEST(RTBioModelScatterPlotExampleTest); - LIT_REGISTER_TEST(VoxelizationValidationTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; } diff --git a/testing/io/itk/CMakeLists.txt b/testing/io/itk/CMakeLists.txt index ae1261b..7bd6d6f 100644 --- a/testing/io/itk/CMakeLists.txt +++ b/testing/io/itk/CMakeLists.txt @@ -1,35 +1,35 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(ITKIO_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbITKIOTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- ADD_TEST(ITKDoseAccessorGeneratorTest ${ITKIO_TEST} ITKDoseAccessorGeneratorTest "${TEST_DATA_ROOT}/Images/ITK/MatchPointLogoSmall.nrrd") ADD_TEST(ITKIOTest ${ITKIO_TEST} ITKIOTest "${TEST_DATA_ROOT}/Images/ITK/MatchPointLogoSmall.nrrd") ADD_TEST(ITKDoseAccessorConverterTest ${ITKIO_TEST} ITKDoseAccessorConverterTest "${TEST_DATA_ROOT}/Dose/DICOM/ConstantTwo.dcm" "${TEST_DATA_ROOT}/Images/ITK/MatchPointLogoSmall.nrrd" ) ADD_TEST(ITKBioModelAccessorConverterTest ${ITKIO_TEST} ITKBioModelAccessorConverterTest "${TEST_DATA_ROOT}/Dose/DICOM/ConstantTwo.dcm") ADD_TEST(ITKMaskAccessorGeneratorTest ${ITKIO_TEST} ITKMaskAccessorGeneratorTest "${TEST_DATA_ROOT}/StructureSet/ITK/Nodes.nrrd") ADD_TEST(ITKMaskAccessorConverterTest ${ITKIO_TEST} ITKMaskAccessorConverterTest "${TEST_DATA_ROOT}/StructureSet/DICOM/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/Dose/DICOM/ConstantTwo.dcm" "${TEST_DATA_ROOT}/StructureSet/ITK/Nodes.nrrd") -RTTB_CREATE_TEST_MODULE(rttbITKIO DEPENDS RTTBITKIO RTTBDicomIO RTTBMasks RTTBOTBMask RTTBBoostMask RTTBModels PACKAGE_DEPENDS Boost Litmus ITK DCMTK) +RTTB_CREATE_TEST_MODULE(rttbITKIO DEPENDS RTTBITKIO RTTBDicomIO RTTBMasks RTTBBoostMask RTTBModels PACKAGE_DEPENDS Boost Litmus ITK DCMTK) diff --git a/testing/io/itk/ITKMaskAccessorConverterTest.cpp b/testing/io/itk/ITKMaskAccessorConverterTest.cpp index 49da530..3d03a6e 100644 --- a/testing/io/itk/ITKMaskAccessorConverterTest.cpp +++ b/testing/io/itk/ITKMaskAccessorConverterTest.cpp @@ -1,180 +1,179 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "litImageTester.h" #include "litTestImageIO.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbInvalidDoseException.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbITKImageMaskAccessorConverter.h" #include "rttbITKImageFileMaskAccessorGenerator.h" -#include "rttbOTBMaskAccessor.h" #include "rttbBoostMaskAccessor.h" namespace rttb { namespace testing { /*!@brief MaskAccessorConverterTest - test the conversion rttb dose accessor ->itk 1) test with dicom file (DicomDoseAccessorGenerator) 2) test with mhd file (ITKImageFileDoseAccessorGenerator) */ int ITKMaskAccessorConverterTest(int argc, char* argv[]) { typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; typedef io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer ITKImageTypePointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: //ARGUMENTS: 1: structure file name // 2: dose1 file name std::string RTStr_FILENAME; std::string RTDose_FILENAME; std::string Mask_FILENAME; if (argc > 3) { RTStr_FILENAME = argv[1]; RTDose_FILENAME = argv[2]; Mask_FILENAME = argv[3]; } //1) Read dicomFile and test getITKImage() io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDose_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTStr_FILENAME.c_str()).generateStructureSet(); MaskAccessorPointer maskAccessorPtr = boost::make_shared (rtStructureSet->getStructure(9), doseAccessor1->getGeometricInfo()); maskAccessorPtr->updateMask();//!Important: Update the mask before conversion. io::itk::ITKImageMaskAccessorConverter maskAccessorConverter(maskAccessorPtr); CHECK_NO_THROW(maskAccessorConverter.process()); CHECK_NO_THROW(maskAccessorConverter.getITKImage()); //2) Read itk image, generate mask and convert it back to itk image, check equal MaskAccessorPointer maskAccessorPtr2 = io::itk::ITKImageFileMaskAccessorGenerator( Mask_FILENAME.c_str()).generateMaskAccessor(); maskAccessorPtr2->updateMask();//!Important: Update the mask before conversion. io::itk::ITKImageMaskAccessorConverter maskAccessorConverter2(maskAccessorPtr2); maskAccessorConverter2.process(); typedef itk::Image< DoseTypeGy, 3 > MaskImageType; typedef itk::ImageFileReader ReaderType; ITKImageTypePointer convertedImagePtr = maskAccessorConverter2.getITKImage(); io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer expectedImage = lit::TestImageIO::readImage( Mask_FILENAME); CHECK_EQUAL(convertedImagePtr->GetOrigin()[0], expectedImage->GetOrigin()[0]); CHECK_EQUAL(convertedImagePtr->GetOrigin()[1], expectedImage->GetOrigin()[1]); CHECK_EQUAL(convertedImagePtr->GetOrigin()[2], expectedImage->GetOrigin()[2]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[0], expectedImage->GetSpacing()[0]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[1], expectedImage->GetSpacing()[1]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[2], expectedImage->GetSpacing()[2]); CHECK_EQUAL(convertedImagePtr->GetLargestPossibleRegion().GetSize()[0], expectedImage->GetLargestPossibleRegion().GetSize()[0]); CHECK_EQUAL(convertedImagePtr->GetLargestPossibleRegion().GetSize()[1], expectedImage->GetLargestPossibleRegion().GetSize()[1]); CHECK_EQUAL(convertedImagePtr->GetLargestPossibleRegion().GetSize()[2], expectedImage->GetLargestPossibleRegion().GetSize()[2]); unsigned int sizeX = convertedImagePtr->GetLargestPossibleRegion().GetSize()[0]; unsigned int sizeY = convertedImagePtr->GetLargestPossibleRegion().GetSize()[1]; unsigned int sizeZ = convertedImagePtr->GetLargestPossibleRegion().GetSize()[2]; io::itk::ITKImageMaskAccessor::ITKMaskImageType::IndexType index; for (unsigned int i = 0; i < 20 && i < sizeX && i < sizeY && i < sizeZ; i++) { index[0] = i; index[1] = i; index[2] = i; if (expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index) <= 1) { CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } for (unsigned int i = 0; i < 20; i++) { index[0] = sizeX - 1 - i; index[1] = sizeY - 1 - i; index[2] = sizeZ - 1 - i; if (expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index) <= 1) { CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } for (unsigned int i = 0; i < 20 && (sizeX / 2 - i) < sizeX && (sizeY / 2 - i) < sizeY && (sizeZ / 2 - i) < sizeZ; i++) { index[0] = sizeX / 2 - i; index[1] = sizeY / 2 - i; index[2] = sizeZ / 2 - i; if (expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index) <= 1) { CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/other/CompareDVH.cpp b/testing/io/other/CompareDVH.cpp index be87039..195b24c 100644 --- a/testing/io/other/CompareDVH.cpp +++ b/testing/io/other/CompareDVH.cpp @@ -1,60 +1,86 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "CompareDVH.h" - +#include namespace rttb { namespace testing { bool checkEqualDVH(DVHPointer aDVH1, DVHPointer aDVH2) { bool result; const double errorConstant = 1e-7; result = lit::AreClose(aDVH1->getDeltaD(), aDVH2->getDeltaD(), errorConstant); result = result && lit::AreClose(aDVH1->getDeltaV(), aDVH2->getDeltaV(), errorConstant); result = result && (aDVH1->getDoseID() == aDVH2->getDoseID()); result = result && (aDVH1->getStructureID() == aDVH2->getStructureID()); result = result && lit::AreClose(aDVH1->getMaximum(), aDVH2->getMaximum(), errorConstant); result = result && lit::AreClose(aDVH1->getMinimum(), aDVH2->getMinimum(), errorConstant); result = result && lit::AreClose(aDVH1->getMean(), aDVH2->getMean(), errorConstant); result = result && (aDVH1->getDataDifferential().size() == aDVH2->getDataDifferential().size()); for (int i = 0; i < aDVH1->getDataDifferential().size(); i++) { result = result && lit::AreClose(aDVH1->getDataDifferential().at(i), aDVH2->getDataDifferential().at(i), errorConstant); } return result; } - }//testing + rttb::testing::DVHPointer computeDiffDVH(DVHPointer aDVH1, DVHPointer aDVH2) + { + if (aDVH1->getDeltaD() == aDVH2->getDeltaD() && aDVH1->getDeltaV() == aDVH2->getDeltaV()){ + + rttb::core::DVH::DataDifferentialType dvhData1 = aDVH1->getDataDifferential(); + rttb::core::DVH::DataDifferentialType dvhData2 = aDVH2->getDataDifferential(); + rttb::core::DVH::DataDifferentialType dvhDataDifference; + + auto it1 = dvhData1.cbegin(); + auto it2 = dvhData2.cbegin(); + + while (it1 != dvhData1.cend() && it2 != dvhData2.cend()) + { + dvhDataDifference.push_back(*it1-*it2); + ++it1; + ++it2; + } + + auto differenceDVH = ::boost::make_shared(dvhDataDifference, aDVH1->getDeltaD(), aDVH1->getDeltaV(), aDVH1->getStructureID(), aDVH1->getDoseID()); + return differenceDVH; + } + else { + return aDVH1; + } + } + + }//testing }//rttb diff --git a/testing/io/other/CompareDVH.h b/testing/io/other/CompareDVH.h index 1622b16..2ac33c6 100644 --- a/testing/io/other/CompareDVH.h +++ b/testing/io/other/CompareDVH.h @@ -1,45 +1,46 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "litCheckMacros.h" #include "rttbDVH.h" #ifndef __DVH_COMPARER_H #define __DVH_COMPARER_H namespace rttb { namespace testing { typedef core::DVH::DVHPointer DVHPointer; - /*! Compare 2 dvhs and return the results. - @result Indicates if the test was successfull (true) or if it failed (false) + /*! Compare 2 DVHs and return the results. + @result Indicates if the test was successful (true) or if it failed (false) */ bool checkEqualDVH(DVHPointer aDVH1, DVHPointer aDVH2); + DVHPointer computeDiffDVH(DVHPointer aDVH1, DVHPointer aDVH2); }//testing }//rttb #endif diff --git a/testing/io/virtuos/CMakeLists.txt b/testing/io/virtuos/CMakeLists.txt index b7b8a4b..dddd058 100644 --- a/testing/io/virtuos/CMakeLists.txt +++ b/testing/io/virtuos/CMakeLists.txt @@ -1,50 +1,50 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(VIRTUOSIO_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbVirtuosIOTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- ADD_TEST(VirtuosDoseAccessorGeneratorTest ${VIRTUOSIO_TEST} VirtuosDoseAccessorGeneratorTest "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.pln" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos.gz") ADD_TEST(VirtuosDoseIOTest ${VIRTUOSIO_TEST} VirtuosDoseIOTest "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.pln" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos.gz") ADD_TEST(VirtuosStructureIOTest ${VIRTUOSIO_TEST} VirtuosStructureIOTest "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.vdx" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.ctx.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.vdx" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.ctx.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos.gz") ADD_TEST(VirtuosStructureSetGeneratorTest ${VIRTUOSIO_TEST} VirtuosStructureSetGeneratorTest "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.vdx" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.ctx.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.vdx" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.ctx.gz" ) #trip data ADD_TEST(TripStructureIOTest ${VIRTUOSIO_TEST} TripStructureIOTest "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.vdx" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.ctx.gz" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.ctx" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/NHHTrip/NHH030101.dos") ADD_TEST(TripDoseIOTest ${VIRTUOSIO_TEST} TripDoseIOTest "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030101.pln" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/NHHTrip/NHH030101.dos") ADD_TEST(VirtuosDVHCalculatorExampleTest ${VIRTUOSIO_TEST} VirtuosDVHCalculatorExampleTest "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.vdx" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.pln" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.ctx.gz" ) -RTTB_CREATE_TEST_MODULE(rttbVirtuosIO DEPENDS RTTBVirtuosIO RTTBMasks RTTBOTBMask RTTBBoostMask PACKAGE_DEPENDS Boost Litmus VirtuosIO) +RTTB_CREATE_TEST_MODULE(rttbVirtuosIO DEPENDS RTTBVirtuosIO RTTBMasks RTTBBoostMask PACKAGE_DEPENDS Boost Litmus VirtuosIO) IF (NOT WIN32) #CMake 3.1 provides target_compile_features(RTTB_Interpolation cxx_auto_type cxx_nullptr cxx_override) to automatically add required compiler flags set(CMAKE_CXX_FLAGS "-std=c++11") ENDIF() diff --git a/testing/io/virtuos/VirtuosDVHCalculatorExampleTest.cpp b/testing/io/virtuos/VirtuosDVHCalculatorExampleTest.cpp index 7c5406a..e2132ee 100644 --- a/testing/io/virtuos/VirtuosDVHCalculatorExampleTest.cpp +++ b/testing/io/virtuos/VirtuosDVHCalculatorExampleTest.cpp @@ -1,132 +1,132 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVHCalculator.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbBoostMaskAccessor.h" #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" #include "rttbVirtuosDoseAccessor.h" #include "rttbVirtuosFileStructureSetGenerator.h" namespace rttb { namespace testing { /*! @brief VirtuosDVHCalculatorExampleTest. Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed! */ int VirtuosDVHCalculatorExampleTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; typedef masks::boost::BoostMaskAccessor::StructTypePointer StructTypePointer; typedef core::DVH::DVHPointer DVHPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: virtuos dose file name // 2: virtuos structure file name // 3: virtuos plan file name // 4: virtuos CT file name std::string Virtuos_Dose_File; std::string Virtuos_Structure_File; std::string Virtuos_Plan_File; std::string Virtuos_CT_File; if (argc > 4) { Virtuos_Dose_File = argv[1]; Virtuos_Structure_File = argv[2]; Virtuos_Plan_File = argv[3]; Virtuos_CT_File = argv[4]; } //Virtuos DVH Test io::virtuos::VirtuosPlanFileDoseAccessorGenerator doseAccessorGeneratorVirtuos(Virtuos_Dose_File, Virtuos_Plan_File); DoseAccessorPointer doseAccessorVirtuos(doseAccessorGeneratorVirtuos.generateDoseAccessor()); StructureSetPointer rtStructureSetVirtuos = io::virtuos::VirtuosFileStructureSetGenerator( Virtuos_Structure_File, Virtuos_CT_File).generateStructureSet(); //create MaskAccessor for structure DARM boost::shared_ptr spMaskAccessorVirtuos = boost::make_shared(rtStructureSetVirtuos->getStructure(4), doseAccessorVirtuos->getGeometricInfo()); spMaskAccessorVirtuos->updateMask(); MaskAccessorPointer spMaskAccessor(spMaskAccessorVirtuos); //create corresponding MaskedDoseIterator boost::shared_ptr spMaskedDoseIteratorTmp = boost::make_shared(spMaskAccessor, doseAccessorVirtuos); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); rttb::core::DVHCalculator* calc; CHECK_NO_THROW(calc = new rttb::core::DVHCalculator(spMaskedDoseIterator, (rtStructureSetVirtuos->getStructure(4))->getUID(), doseAccessorVirtuos->getUID())); DVHPointer dvhPtr; CHECK_NO_THROW(dvhPtr = calc->generateDVH()); CHECK_CLOSE(4.08178, dvhPtr->getMaximum(), errorConstant); CHECK_CLOSE(0.0151739, dvhPtr->getMinimum(), errorConstant); CHECK_CLOSE(0.755342, dvhPtr->getMean(), errorConstant); CHECK_CLOSE(0.440044, dvhPtr->getMedian(), errorConstant); CHECK_CLOSE(0.0151739, dvhPtr->getModal(), errorConstant); CHECK_CLOSE(0.835792, dvhPtr->getStdDeviation(), errorConstant); CHECK_CLOSE(0.698549, dvhPtr->getVariance(), errorConstant); - CHECK_CLOSE(46573.0193175, dvhPtr->getNumberOfVoxels(), errorConstant); + CHECK_CLOSE(46573.01838, dvhPtr->getNumberOfVoxels(), errorConstant); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/models/rttbScatterTester.h b/testing/models/rttbScatterTester.h index ba746df..376ab91 100644 --- a/testing/models/rttbScatterTester.h +++ b/testing/models/rttbScatterTester.h @@ -1,111 +1,110 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __SCATTER_TESTER_H #define __SCATTER_TESTER_H #include "litTesterBase.h" #include "litString.h" #include "rttbBaseType.h" #include "rttbBioModelScatterPlots.h" #include "rttbBioModelCurve.h" namespace rttb { namespace testing { /*! class ScatterTester @brief Tester class for for model scatter plots. Compares a given scatter plot with a given model curve. The values should be similar for similar doses. Variations should only depend on the variance given for the scatter plot calculation. An additional deviation of 1e-4+givenVariance is ignored. */ class ScatterTester: public lit::TesterBase { private: models::CurveDataType _referenceCurve; models::ScatterPlotType _compareScatter; /*! Additional variance that is allowed in the comparison. This value usually corresponds to the value used in the generation of the scatter plot. */ models::BioModelParamType _variance; mutable float _maxDifference; mutable int _numDifference; mutable float _meanDifference; /*! If true allows up to 5% of the scatter points to deviate without failing. If false, all points have to correspond. */ bool _allowExceptions; public: ScatterTester(models::CurveDataType aReferenceCurve, models::ScatterPlotType aCompareScatter, models::BioModelParamType aVariance = 0); /*! Set the reference curve used in comparison. */ void setReferenceCurve(const models::CurveDataType aReferenceCurve); /*! Set the scatter data used in comparison. */ void setCompareScatter(const models::ScatterPlotType aCompareScatter); /*! Set the variance that is allowed for the scatter plot. Usually this matches the parameter used in the computation of the scattered values. */ void setVariance(const models::BioModelParamType aVariance); /*! If true allows up tp 5% of the scatter points to deviate without failing. If false, all points have to correspond. */ void setAllowExceptions(const bool allow); /*! Returns a string that specifies the test the tester currently performs. */ lit::StringType getTestDescription(void) const; lit::StringType getTestName(void) const { return "ScatterTester"; }; protected: /*! performes the test and checks the results. @result Indicates if the test was successfull (true) or if it failed (false) */ bool doCheck(void) const; /*! Function will be called be check() if test was succesfull. */ void handleSuccess(void) const; /*! Function will be called be check() if test was a failure. */ void handleFailure(void) const; }; - } } #endif \ No newline at end of file diff --git a/testing/validation/CMakeLists.txt b/testing/validation/CMakeLists.txt new file mode 100644 index 0000000..400e75e --- /dev/null +++ b/testing/validation/CMakeLists.txt @@ -0,0 +1,28 @@ +#----------------------------------------------------------------------------- +# Setup the system information test. Write out some basic failsafe +# information in case the test doesn't run. +#----------------------------------------------------------------------------- + + +SET(CORE_TEST_VALIDATION ${EXECUTABLE_OUTPUT_PATH}/rttbValidationTests) + +SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) + +SET(TEMP ${RTTBTesting_BINARY_DIR}/Temporary) + + +#----------------------------------------------------------------------------- + +ADD_TEST(VoxelizationDVHComparisonTest ${CORE_TEST_VALIDATION} VoxelizationDVHComparisonTest +"${TEST_DATA_ROOT}/StructureSet/DICOM/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/Dose/DICOM/LinearIncrease3D.dcm" +"${TEST_DATA_ROOT}/DVH/XML/1.3.6.1.4.1.2452.6.2037938358.1234393433.864109958.30410275/OTBMask/" +"${TEST_DATA_ROOT}/DVH/XML/1.3.6.1.4.1.2452.6.2037938358.1234393433.864109958.30410275/BoostMask/" +"${TEST_DATA_ROOT}/DVH/XML/1.3.6.1.4.1.2452.6.2037938358.1234393433.864109958.30410275/BoostMaskRedesign/") +ADD_TEST(VoxelizationValidationTest ${CORE_TEST_VALIDATION} VoxelizationValidationTest +"${TEST_DATA_ROOT}/StructureSet/DICOM/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" +"${TEST_DATA_ROOT}/Dose/DICOM/LinearIncrease3D.dcm" "${TEST_DATA_ROOT}/Mask/1.3.6.1.4.1.2452.6.2037938358.1234393433.864109958.30410275/BoostMask/" +"${TEST_DATA_ROOT}/Mask/1.3.6.1.4.1.2452.6.2037938358.1234393433.864109958.30410275/OTBMask/" "${TEST_DATA_ROOT}/Mask/1.3.6.1.4.1.2452.6.2037938358.1234393433.864109958.30410275/BoostMaskRedesign/" +"${TEST_DATA_ROOT}/Dose/DICOM/PatBM116__RTDOSE_Main_corr.mhd" "${TEST_DATA_ROOT}/StructureSet/DICOM/__1__mm__1.2.276.0.28.19.640188827224102750711261838091512821903075578763.4195312189") + +RTTB_CREATE_TEST_MODULE(rttbValidation DEPENDS RTTBCore RTTBBoostMask RTTBDicomIO RTTBITKIO RTTBOtherIO PACKAGE_DEPENDS Litmus ITK) + diff --git a/testing/validation/VoxelizationDVHComparisonTest.cpp b/testing/validation/VoxelizationDVHComparisonTest.cpp new file mode 100644 index 0000000..c2b7c38 --- /dev/null +++ b/testing/validation/VoxelizationDVHComparisonTest.cpp @@ -0,0 +1,178 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 1333 $ (last changed revision) +// @date $Date: 2016-04-22 11:12:14 +0200 (Fr, 22 Apr 2016) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + +// this file defines the rttbCoreTests for the test driver +// and all it expects is that you have a function called RegisterTests + +#include +#include +#include +#include + +#include "litCheckMacros.h" + +#include "rttbGenericMaskedDoseIterator.h" +#include "rttbGenericDoseIterator.h" +#include "rttbDicomDoseAccessor.h" +#include "rttbDicomFileDoseAccessorGenerator.h" +#include "rttbDicomFileStructureSetGenerator.h" +#include "rttbDVHCalculator.h" +#include "rttbBoostMaskAccessor.h" +#include "rttbDVHXMLFileWriter.h" +#include "rttbDVHXMLFileReader.h" +#include "../io/other/CompareDVH.h" + +namespace rttb +{ + + namespace testing + { + + /*! @brief VoxelizationDVHComparisonTests. + Computes the DVH difference of different voxelizations (OTB/Boost legacy/Boost) + Writes the difference in a DVH and saves in a file + */ + + + core::DoseIteratorInterface::DoseIteratorPointer createMaskDoseIterator(masks::boost::BoostMaskAccessor::StructTypePointer rtstruct, + core::GenericDoseIterator::DoseAccessorPointer doseAccessor, const std::string& voxelizationType) + { + core::GenericMaskedDoseIterator::MaskAccessorPointer spMaskAccessor; + if (voxelizationType == "BoostRedesign"){ + auto spBoostRedesignMaskAccessor = + ::boost::make_shared(rtstruct, doseAccessor->getGeometricInfo()); + spBoostRedesignMaskAccessor->updateMask(); + spMaskAccessor = spBoostRedesignMaskAccessor; + } + + auto spMaskedDoseIteratorTmp = + ::boost::make_shared(spMaskAccessor, doseAccessor); + core::DoseIteratorInterface::DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); + return spMaskedDoseIterator; + } + + rttb::core::DVH calcDVH(core::DVHCalculator::DoseIteratorPointer doseIterator, const IDType& structUID, const IDType& doseUID) + { + rttb::core::DVHCalculator calc(doseIterator, structUID, doseUID); + rttb::core::DVH dvh = *(calc.generateDVH()); + return dvh; + } + + void writeCumulativeDVH(const std::string& filename, rttb::core::DVH dvh) + { + DVHType typeCum = { DVHType::Cumulative }; + io::other::DVHXMLFileWriter dvhWriter(filename, typeCum); + dvhWriter.writeDVH(boost::make_shared(dvh)); + } + + + int VoxelizationDVHComparisonTest(int argc, char* argv[]) + { + typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; + typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; + typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; + typedef core::DVHCalculator::MaskedDoseIteratorPointer MaskedDoseIteratorPointer; + typedef masks::boost::BoostMaskAccessor::StructTypePointer StructTypePointer; + typedef core::DVH::DVHPointer DVHPointer; + typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; + + PREPARE_DEFAULT_TEST_REPORTING; + + std::string RTSTRUCT_FILENAME; + std::string RTDOSE_FILENAME; + std::string RTDVH_XML_OTB_DIRECTORY; + std::string RTDVH_XML_BOOST_DIRECTORY; + std::string RTDVH_XML_BOOSTREDESIGN_DIRECTORY; + + if (argc > 5) + { + RTSTRUCT_FILENAME = argv[1]; + RTDOSE_FILENAME = argv[2]; + RTDVH_XML_OTB_DIRECTORY = argv[3]; + RTDVH_XML_BOOST_DIRECTORY = argv[4]; + RTDVH_XML_BOOSTREDESIGN_DIRECTORY = argv[5]; + } + + // read dicom-rt dose + io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); + + DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); + + //create a vector of MaskAccessors (one for each structure) + StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( + RTSTRUCT_FILENAME.c_str()).generateStructureSet(); + + //start evaluation + clock_t start(clock()); + + if (rtStructureSet->getNumberOfStructures() > 0) + { + for (int j = 0; j < static_cast(rtStructureSet->getNumberOfStructures()); j++) + { + std::cout << rtStructureSet->getStructure(j)->getLabel() << std::endl; + + auto spMaskedDoseIteratorBoostRedesign = createMaskDoseIterator(rtStructureSet->getStructure(j), doseAccessor1, "BoostRedesign"); + + auto label = rtStructureSet->getStructure(j)->getLabel(); + ::boost::replace_all(label, "/", "_"); + boost::filesystem::path dvhOTBFilename(RTDVH_XML_OTB_DIRECTORY); + dvhOTBFilename /= "DVH_" + label + ".xml"; + + boost::filesystem::path dvhBoostFilename(RTDVH_XML_BOOST_DIRECTORY); + dvhBoostFilename /= "DVH_" + label + ".xml"; + + io::other::DVHXMLFileReader dvhReaderOTB(dvhOTBFilename.string()); + auto dvhOTB = dvhReaderOTB.generateDVH(); + + io::other::DVHXMLFileReader dvhReaderBoost(dvhBoostFilename.string()); + auto dvhBoost = dvhReaderBoost.generateDVH(); + + auto dvhBoostRedesign = calcDVH(spMaskedDoseIteratorBoostRedesign, (rtStructureSet->getStructure(j))->getUID(), doseAccessor1->getUID()); + boost::filesystem::path dvhBoostRedesignFilename(RTDVH_XML_BOOSTREDESIGN_DIRECTORY); + dvhBoostRedesignFilename /= "DVH_" + label + ".xml"; + writeCumulativeDVH(dvhBoostRedesignFilename.string(), dvhBoostRedesign); + + std::cout << "=== Dose 1 Structure " << j << "===" << std::endl; + std::cout << "with OTB voxelization: " << std::endl; + std::cout << dvhOTB << std::endl; + std::cout << "with Boost voxelization: " << std::endl; + std::cout << dvhBoost << std::endl; + std::cout << "with BoostRedesign voxelization: " << std::endl; + std::cout << dvhBoostRedesign << std::endl; + + //compare DVH for different voxelizations + auto diffDVH = computeDiffDVH(dvhOTB, boost::make_shared(dvhBoostRedesign)); + boost::filesystem::path dvhBoostRedesignDiffFilename(RTDVH_XML_BOOSTREDESIGN_DIRECTORY); + dvhBoostRedesignDiffFilename /= "DVHDiff_" + label + ".xml"; + writeCumulativeDVH(dvhBoostRedesignDiffFilename.string(), *diffDVH); + } + } + + clock_t finish(clock()); + + std::cout << "DVH Calculation time: " << finish - start << " ms" << std::endl; + + RETURN_AND_REPORT_TEST_SUCCESS; + } + + }//testing +}//rttb + diff --git a/testing/validation/VoxelizationValidationTest.cpp b/testing/validation/VoxelizationValidationTest.cpp new file mode 100644 index 0000000..f93aacd --- /dev/null +++ b/testing/validation/VoxelizationValidationTest.cpp @@ -0,0 +1,191 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 1495 $ (last changed revision) +// @date $Date: 2016-09-29 16:17:47 +0200 (Do, 29 Sep 2016) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + +// this file defines the rttbCoreTests for the test driver +// and all it expects is that you have a function called RegisterTests + +#include +#include +#include + +#include "litCheckMacros.h" + +#include "rttbBaseType.h" +#include "rttbGenericMaskedDoseIterator.h" +#include "rttbGenericDoseIterator.h" +#include "rttbDicomDoseAccessor.h" +#include "rttbDicomFileDoseAccessorGenerator.h" +#include "rttbDicomFileStructureSetGenerator.h" +#include "rttbBoostMaskAccessor.h" +#include "rttbITKImageMaskAccessorConverter.h" +#include "rttbImageWriter.h" +#include "rttbBoostMask.h" +#include "rttbBoostMaskAccessor.h" +#include "rttbITKImageAccessorGenerator.h" +#include "rttbITKImageFileAccessorGenerator.h" +#include "rttbInvalidParameterException.h" + +#include "itkSubtractImageFilter.h" +#include "itkImageFileReader.h" + +namespace rttb +{ + + namespace testing + { + io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer subtractImages(const io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer image1, const io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer image2) + { + typedef itk::SubtractImageFilter + SubtractImageFilterType; + + SubtractImageFilterType::Pointer subtractFilter = SubtractImageFilterType::New(); + subtractFilter->SetInput1(image1); + subtractFilter->SetInput2(image2); + //since the image origin may be modified through the writing process a bit + subtractFilter->SetCoordinateTolerance(5e-2); + subtractFilter->Update(); + + return subtractFilter->GetOutput(); + } + + + /*! @brief VoxelizationValidationTest. + Compare the new boost voxelization to the OTB voxelization + Check the creating of new boost masks for files where the old boost voxelization failed. + */ + int VoxelizationValidationTest(int argc, char* argv[]) + { + PREPARE_DEFAULT_TEST_REPORTING; + + typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; + typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; + typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; + + std::string RTSTRUCT_FILENAME; + std::string RTDOSE_FILENAME; + std::string BoostMask_DIRNAME; + std::string OTBMask_DIRNAME; + std::string BoostMaskRedesign_DIRNAME; + + std::string RTDose_BoostRedesign; + std::string RTStr_BoostRedesign; + + if (argc > 7) + { + RTSTRUCT_FILENAME = argv[1]; + RTDOSE_FILENAME = argv[2]; + BoostMask_DIRNAME = argv[3]; + OTBMask_DIRNAME = argv[4]; + BoostMaskRedesign_DIRNAME = argv[5]; + RTDose_BoostRedesign = argv[6]; + RTStr_BoostRedesign = argv[7]; + } + + OFCondition status; + DcmFileFormat fileformat; + + /* read dicom-rt dose */ + io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); + DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); + + //create a vector of MaskAccessors (one for each structure) + StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( + RTSTRUCT_FILENAME.c_str()).generateStructureSet(); + + if (rtStructureSet->getNumberOfStructures() > 0) + { + //do not compute struct "Aussenkontur" since it is very large (15000 cm³) + for (size_t j = 1; j < rtStructureSet->getNumberOfStructures(); j++) + { + std::cout << j << ": " << rtStructureSet->getStructure(j)->getLabel() << std::endl; + + //read OTB mask image + boost::filesystem::path otbMaskFilename(OTBMask_DIRNAME); + otbMaskFilename /= boost::lexical_cast(j)+".mhd"; + + typedef itk::ImageFileReader ReaderType; + + ReaderType::Pointer readerOTB = ReaderType::New(); + readerOTB->SetFileName(otbMaskFilename.string()); + readerOTB->Update(); + const io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer otbMaskImage = readerOTB->GetOutput(); + + //create Boost MaskAccessor redesign + clock_t startR(clock()); + + MaskAccessorPointer boostMaskRPtr + = ::boost::make_shared + (rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); + CHECK_NO_THROW(boostMaskRPtr->updateMask()); + + clock_t finishR(clock()); + std::cout << "Boost Mask Redesign Calculation: " << finishR - startR << " ms" << + std::endl; + + + rttb::io::itk::ITKImageMaskAccessorConverter itkConverterR(boostMaskRPtr); + CHECK(itkConverterR.process()); + + boost::filesystem::path redesignFilename(BoostMaskRedesign_DIRNAME); + redesignFilename /= boost::lexical_cast(j)+".nrrd"; + rttb::io::itk::ImageWriter writerR(redesignFilename.string(), itkConverterR.getITKImage()); + CHECK(writerR.writeFile()); + + auto subtractedRedesignImage = subtractImages(otbMaskImage, itkConverterR.getITKImage()); + + boost::filesystem::path subtractRedesignFilename(BoostMaskRedesign_DIRNAME); + subtractRedesignFilename /= boost::lexical_cast(j) + "_subtracted.nrrd"; + rttb::io::itk::ImageWriter writerRSubtracted(subtractRedesignFilename.string(), subtractedRedesignImage); + + CHECK(writerRSubtracted.writeFile()); + } + } + + /* Exception tests using data with different z spacing of dose and structure */ + io::itk::ITKImageFileAccessorGenerator doseAccessorGenerator2(RTDose_BoostRedesign.c_str()); + DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); + + StructureSetPointer rtStructureSet2 = io::dicom::DicomFileStructureSetGenerator( + RTStr_BoostRedesign.c_str()).generateStructureSet(); + + + if (rtStructureSet2->getNumberOfStructures() > 0) + { + for (size_t j = 12; j < 26; j++) + { + std::cout << j << ": " << rtStructureSet2->getStructure(j)->getLabel() << std::endl; + + //create Boost MaskAccessor redesign + MaskAccessorPointer boostMaskAccessorRedesignPtr + = ::boost::make_shared + (rtStructureSet2->getStructure(j), doseAccessor2->getGeometricInfo()); + + //No exception using redesigned boost mask + CHECK_NO_THROW(boostMaskAccessorRedesignPtr->updateMask()); + } + } + + RETURN_AND_REPORT_TEST_SUCCESS; + } + + }//testing +}//rttb + diff --git a/testing/validation/files.cmake b/testing/validation/files.cmake new file mode 100644 index 0000000..b489d59 --- /dev/null +++ b/testing/validation/files.cmake @@ -0,0 +1,10 @@ +SET(CPP_FILES + VoxelizationDVHComparisonTest.cpp + VoxelizationValidationTest.cpp + ../io/other/CompareDVH.cpp + rttbValidationTests.cpp + ) + +SET(H_FILES + ../io/other/CompareDVH.h +) diff --git a/testing/examples/rttbTestExamples.cpp b/testing/validation/rttbValidationTests.cpp similarity index 67% copy from testing/examples/rttbTestExamples.cpp copy to testing/validation/rttbValidationTests.cpp index 6595247..352b629 100644 --- a/testing/examples/rttbTestExamples.cpp +++ b/testing/validation/rttbValidationTests.cpp @@ -1,76 +1,65 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @version $Revision: 1388 $ (last changed revision) +// @date $Date: 2016-07-04 14:03:35 +0200 (Mo, 04 Jul 2016) $ (last change date) +// @author $Author: hentsch $ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "litMultiTestsMain.h" #include "RTToolboxConfigure.h" namespace rttb { namespace testing { void registerTests() { - LIT_REGISTER_TEST(RTBioModelExampleTest); - LIT_REGISTER_TEST(DVHCalculatorExampleTest); - LIT_REGISTER_TEST(RTDVHTest); - LIT_REGISTER_TEST(RTDoseIndexTest); - - if (RTTB_VIRTUOS_SUPPORT) - { - LIT_REGISTER_TEST(RTDoseStatisticsVirtuosTest); - } - - LIT_REGISTER_TEST(RTDoseStatisticsDicomTest); - LIT_REGISTER_TEST(RTBioModelScatterPlotExampleTest); - LIT_REGISTER_TEST(VoxelizationValidationTest); + LIT_REGISTER_TEST(VoxelizationDVHComparisonTest); + LIT_REGISTER_TEST(VoxelizationValidationTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; }