diff --git a/demoapps/DoseTool/DoseToolHelper.cpp b/demoapps/DoseTool/DoseToolHelper.cpp index 9f1724b..09a9a09 100644 --- a/demoapps/DoseTool/DoseToolHelper.cpp +++ b/demoapps/DoseTool/DoseToolHelper.cpp @@ -1,251 +1,260 @@ // ----------------------------------------------------------------------- // 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: 1095 $ (last changed revision) // @date $Date: 2015-09-11 11:12:40 +0200 (Fr, 11 Sep 2015) $ (last change date) // @author $Author: hentsch $ (last changed by) */ #include "DoseToolHelper.h" #include "boost/make_shared.hpp" #include "boost/shared_ptr.hpp" #include "boost/property_tree/ptree.hpp" #include "rttbExceptionMacros.h" #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomHelaxFileDoseAccessorGenerator.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbStructureSetGeneratorInterface.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbVirtuosFileStructureSetGenerator.h" #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbDoseStatisticsXMLWriter.h" #include "rttbVOIindexIdentifier.h" rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadDose(const std::string& fileName, const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args) { rttb::core::DoseAccessorInterface::DoseAccessorPointer result; std::cout << std::endl << "read dose file... "; if (args.empty() || args[0] == "dicom") { std::cout << "use RTTB dicom IO... "; result = loadDicomDose(fileName); } else if (args[0] == "helax") { std::cout << "use RTTB Helax IO... "; result = loadHelaxDose(fileName); } else if (args[0] == "itk") { std::cout << "use RTTB itk IO... "; result = loadITKDose(fileName); } else if (args[0] == "virtuos") { if (args.size() < 2) { rttbDefaultExceptionStaticMacro( << "Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io stlye argument."); } std::cout << "use RTTB virtuos IO... " << std::endl; std::cout << " virtuos plan file: " << args[1] << " ... "; result = loadVirtuosDose(fileName, args[1]); } else { rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " << args[0]); } std::cout << "done." << std::endl; return result; }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadDicomDose(const std::string& fileName) { rttb::io::dicom::DicomFileDoseAccessorGenerator generator(fileName); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadHelaxDose(const std::string& path) { rttb::io::helax::DicomHelaxFileDoseAccessorGenerator generator(path); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadITKDose(const std::string& fileName) { rttb::io::itk::ITKImageFileAccessorGenerator generator(fileName); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadVirtuosDose(const std::string& fileName, const std::string& planFileName) { rttb::io::virtuos::VirtuosPlanFileDoseAccessorGenerator generator(fileName, planFileName); return generator.generateDoseAccessor(); }; rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadStruct( const std::string& fileName, const ApplicationData::LoadingStyleArgType& args) { rttb::core::StructureSetGeneratorInterface::StructureSetPointer result; std::cout << std::endl << "read struct file... "; if (args.empty() || args[0] == "dicom") { std::cout << "use RTTB dicom IO... "; result = loadDicomStruct(fileName); } else if (args[0] == "virtuos") { std::cout << "use RTTB virtuos IO... " << std::endl; std::cout << " virtuos CTX file: " << args[1] << " ... "; result = loadVirtuosStruct(fileName, args[1]); } else { rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " << args[0]); } std::cout << "done." << std::endl; return result; } rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadDicomStruct( const std::string& fileName) { rttb::io::dicom::DicomFileStructureSetGenerator generator(fileName); return generator.generateStructureSet(); } rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadVirtuosStruct( const std::string& fileName, const std::string& ctxFileName) { rttb::io::virtuos::VirtuosFileStructureSetGenerator generator(fileName, ctxFileName.c_str()); return generator.generateStructureSet(); } void rttb::apps::doseTool::processData(rttb::apps::doseTool::ApplicationData& appData) { std::cout << std::endl << "generating mask... "; core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr = generateMask(appData); core::DoseIteratorInterface::DoseIteratorPointer spDoseIterator(generateMaskedDoseIterator(maskAccessorPtr, appData._dose)); std::cout << "done." << std::endl; std::cout << std::endl << "computing dose statistics... "; - algorithms::DoseStatistics::DoseStatisticsPointer statistics = computeDoseStatistics(spDoseIterator, - appData._computeComplexDoseStatistics); + algorithms::DoseStatistics::DoseStatisticsPointer statistics = calculateDoseStatistics(spDoseIterator, + appData._computeComplexDoseStatistics, appData._prescribedDose); std::cout << "done." << std::endl; std::cout << std::endl << "writing dose statistics to file... "; writeDoseStatisticsFile(statistics, appData); std::cout << "done." << std::endl; }; void rttb::apps::doseTool::determineStructIndex(rttb::apps::doseTool::ApplicationData& appData) { unsigned int index = rttb::masks::VOIindexIdentifier::getIndexByVoiName(appData._struct, appData._structNameRegex); appData._structIndex = index; appData._structNameActual = appData._struct->getStructure(index)->getLabel(); } rttb::core::MaskAccessorInterface::MaskAccessorPointer rttb::apps::doseTool::generateMask( rttb::apps::doseTool::ApplicationData& appData) { core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr; if (appData._structLoadStyle.front() == "itk") { maskAccessorPtr = rttb::io::itk::ITKImageFileMaskAccessorGenerator(appData._structFileName).generateMaskAccessor(); } else { determineStructIndex(appData); bool strict = !appData._allowSelfIntersection; maskAccessorPtr = boost::make_shared (appData._struct->getStructure(appData._structIndex), appData._dose->getGeometricInfo(), strict); } maskAccessorPtr->updateMask(); return maskAccessorPtr; } rttb::core::DoseIteratorInterface::DoseIteratorPointer rttb::apps::doseTool::generateMaskedDoseIterator( rttb::core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr, rttb::core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr) { boost::shared_ptr maskedDoseIterator = boost::make_shared(maskAccessorPtr, doseAccessorPtr); rttb::core::DoseIteratorInterface::DoseIteratorPointer doseIterator(maskedDoseIterator); return doseIterator; } -rttb::algorithms::DoseStatistics::DoseStatisticsPointer rttb::apps::doseTool::computeDoseStatistics( - core::DoseIteratorInterface::DoseIteratorPointer doseIterator, bool computeComplexDoseStatistics) +rttb::algorithms::DoseStatistics::DoseStatisticsPointer rttb::apps::doseTool::calculateDoseStatistics( + core::DoseIteratorInterface::DoseIteratorPointer doseIterator, bool calculateComplexDoseStatistics, + DoseTypeGy prescribedDose) { rttb::algorithms::DoseStatisticsCalculator doseStatsCalculator(doseIterator); - return doseStatsCalculator.calculateDoseStatistics(computeComplexDoseStatistics); + + if (calculateComplexDoseStatistics) + { + return doseStatsCalculator.calculateDoseStatistics(prescribedDose); + } + else + { + return doseStatsCalculator.calculateDoseStatistics(); + } } void rttb::apps::doseTool::writeDoseStatisticsFile(rttb::algorithms::DoseStatistics::DoseStatisticsPointer statistics, rttb::apps::doseTool::ApplicationData& appData) { boost::property_tree::ptree originalTree = rttb::io::other::writeDoseStatistics(statistics); //add config part to xml originalTree.add("statistics.config.requestedStructRegex", appData._structNameRegex); originalTree.add("statistics.config.structName", appData._structNameActual); originalTree.add("statistics.config.doseUID", appData._dose->getUID()); originalTree.add("statistics.config.doseFile", appData._doseFileName); originalTree.add("statistics.config.structFile", appData._structFileName); boost::property_tree::ptree reorderedTree, configTree, resultsTree; configTree = originalTree.get_child("statistics.config"); resultsTree = originalTree.get_child("statistics.results"); reorderedTree.add_child("statistics.config", configTree); reorderedTree.add_child("statistics.results", resultsTree); boost::property_tree::write_xml(appData._outputFileName, reorderedTree, std::locale(), boost::property_tree::xml_writer_make_settings('\t', 1)); } diff --git a/demoapps/DoseTool/DoseToolHelper.h b/demoapps/DoseTool/DoseToolHelper.h index 48dd667..b81a178 100644 --- a/demoapps/DoseTool/DoseToolHelper.h +++ b/demoapps/DoseTool/DoseToolHelper.h @@ -1,117 +1,118 @@ // ----------------------------------------------------------------------- // 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: 1066 $ (last changed revision) // @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) // @author $Author: floca $ (last changed by) */ #ifndef __DOSETOOL_HELPER_H #define __DOSETOOL_HELPER_H #include "DoseToolApplicationData.h" #include "rttbDoseAccessorInterface.h" #include "rttbDoseIteratorInterface.h" #include "rttbMaskAccessorInterface.h" #include "rttbDoseStatistics.h" namespace rttb { namespace apps { namespace doseTool { /*! @brief loads a dose from a file based on the loadingStyle. @exception Throws an rttb::Exception if loading fails */ core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName, const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args); /*! @brief loads a dicom dose from a file. @exception Throws an rttb::Exception if loading fails @sa DicomFileDoseAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadDicomDose(const std::string& fileName); /*! @brief loads a helax dose from a file. @exception Throws an rttb::Exception if loading fails @sa DicomHelaxFileDoseAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadHelaxDose(const std::string& path); /*! @brief loads an itk dose from a file. @exception Throws an rttb::Exception if loading fails. @details Might be of all formats that ITK know (*.mhd, *.nrrd, ...). The absolute image values are taken as dose. @sa ITKImageFileAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadITKDose(const std::string& fileName); /*! @brief loads a virtuos dose from a file. @exception Throws an rttb::Exception if loading fails @sa VirtuosPlanFileDoseAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, const std::string& planFileName); /*! @brief loads a struct from a file based on the loadingStyle. @exception Throws an rttb::Exception if loading fails @details voxelized itk images are read in generateMask() directly */ core::StructureSetGeneratorInterface::StructureSetPointer loadStruct(const std::string& fileName, const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args); /*! @brief loads a dicom struct from a file. @exception Throws an rttb::Exception if loading fails @sa DicomFileStructureSetGenerator */ core::StructureSetGeneratorInterface::StructureSetPointer loadDicomStruct(const std::string& fileName); /*! @brief loads a virtuos struct from a file. @exception Throws an rttb::Exception if loading fails @sa VirtuosPlanFileDoseAccessorGenerator */ core::StructureSetGeneratorInterface::StructureSetPointer loadVirtuosStruct(const std::string& fileName, const std::string& ctxFileName); /*! @brief Contains the business logic of processing all information to calculate the dose statistics and writing them to an xml file. @details Uses appData for the input data and the correct configuration. */ void processData(ApplicationData& appData); /*! @brief Searches for the struct index based on the regex */ void determineStructIndex(ApplicationData& appData); /*! @brief Generates a mask from the struct file by using the boostAccessor. In case of itk image, it directly loads the voxelized image. */ core::MaskAccessorInterface::MaskAccessorPointer generateMask(ApplicationData& appData); - algorithms::DoseStatistics::DoseStatisticsPointer computeDoseStatistics(core::DoseIteratorInterface::DoseIteratorPointer - doseIterator, bool computeComplexDoseStatistics); + algorithms::DoseStatistics::DoseStatisticsPointer calculateDoseStatistics( + core::DoseIteratorInterface::DoseIteratorPointer + doseIterator, bool calculateComplexDoseStatistics, DoseTypeGy prescribedDose); /*! @brief Writes the dose statistics as XML to a file @details adds a .... part to the RTTB generated xml where the used files and struct names are stored. */ void writeDoseStatisticsFile(algorithms::DoseStatistics::DoseStatisticsPointer statistics, rttb::apps::doseTool::ApplicationData& appData); core::DoseIteratorInterface::DoseIteratorPointer generateMaskedDoseIterator( core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr, core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr); } } } #endif diff --git a/testing/demoapps/DoseTool/CMakeLists.txt b/testing/demoapps/DoseTool/CMakeLists.txt index 3840e5e..535caf0 100644 --- a/testing/demoapps/DoseTool/CMakeLists.txt +++ b/testing/demoapps/DoseTool/CMakeLists.txt @@ -1,32 +1,32 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(DOSETOOL_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbDoseToolTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- IF(MSVC) ADD_DEFINITIONS(/bigobj) ENDIF() ADD_TEST(DoseToolBasicUsageTest ${DOSETOOL_TEST} DoseToolBasicUsageTest) ADD_TEST(DoseToolInvalidParametersTest ${DOSETOOL_TEST} DoseToolInvalidParametersTest) -ADD_TEST(DoseToolVirtuosDoseVirtuosStructTest ${DOSETOOL_TEST} DoseToolVirtuosDoseTest "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa101.pln" - "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.vdx" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.ctx.gz" "HERZ" +ADD_TEST(DoseToolVirtuosDoseVirtuosStructTest ${DOSETOOL_TEST} DoseToolVirtuosDoseTest "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.pln" + "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.vdx" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.ctx.gz" "DARM" "${TEST_DATA_ROOT}/DoseStatistics/virtuos.xml" "${TEST_DATA_ROOT}/DoseStatistics/virtuosComplex.xml") ADD_TEST(DoseToolDicomDoseDicomStructTest ${DOSETOOL_TEST} DoseToolDicomDoseTest "${TEST_DATA_ROOT}/DICOM/TestDose/dicompylerTestDose.dcm" "${TEST_DATA_ROOT}/DICOM/StructureSet/rtss.dcm" "Nodes" "${TEST_DATA_ROOT}/DoseStatistics/dicom.xml" "${TEST_DATA_ROOT}/DoseStatistics/dicomComplex.xml") ADD_TEST(DoseToolITKDoseDicomStructTest ${DOSETOOL_TEST} DoseToolITKDoseTest "${TEST_DATA_ROOT}/ITK/dicompylerTestDose.mhd" "${TEST_DATA_ROOT}/DICOM/StructureSet/rtss.dcm" "" "Nodes" "${TEST_DATA_ROOT}/DoseStatistics/itkDicomStruct.xml" "${TEST_DATA_ROOT}/DoseStatistics/itkDicomStructComplex.xml") -ADD_TEST(DoseToolITKDoseVirtuosStructTest ${DOSETOOL_TEST} DoseToolITKDoseTest "${TEST_DATA_ROOT}/ITK/virtuosTestDose.mhd" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.vdx" - "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.ctx.gz" "HERZ" "${TEST_DATA_ROOT}/DoseStatistics/itkVirtuosStruct.xml" "${TEST_DATA_ROOT}/DoseStatistics/itkVirtuosStructComplex.xml") +ADD_TEST(DoseToolITKDoseVirtuosStructTest ${DOSETOOL_TEST} DoseToolITKDoseTest "${TEST_DATA_ROOT}/ITK/virtuosTestDose.mhd" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.vdx" + "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.ctx.gz" "DARM" "${TEST_DATA_ROOT}/DoseStatistics/itkVirtuosStruct.xml" "${TEST_DATA_ROOT}/DoseStatistics/itkVirtuosStructComplex.xml") RTTB_CREATE_APPLICATION_TESTS(DoseTool PACKAGE_DEPENDS Litmus BoostBinaries)