diff --git a/apps/DoseTool/CMakeLists.txt b/apps/DoseTool/CMakeLists.txt index d99c129..3c5b6a4 100644 --- a/apps/DoseTool/CMakeLists.txt +++ b/apps/DoseTool/CMakeLists.txt @@ -1,4 +1,4 @@ MESSAGE (STATUS "generating app: DoseTool - calculating dose statistics and DVH") SET(RTTB_Boost_ADDITIONAL_COMPONENT program_options) -RTTB_CREATE_APPLICATION(DoseTool DEPENDS RTTBCore RTTBMasks RTTBMasks RTTBBoostMask RTTBOtherIO RTTBAlgorithms RTTBUtilsIO PACKAGE_DEPENDS ArgumentParsingLib BoostBinaries) +RTTB_CREATE_APPLICATION(DoseTool DEPENDS RTTBCore RTTBBoostMask RTTBOtherIO RTTBAlgorithms RTTBUtilsIO PACKAGE_DEPENDS ArgumentParsingLib BoostBinaries) diff --git a/apps/DoseTool/DoseToolApplicationData.cpp b/apps/DoseTool/DoseToolApplicationData.cpp index 112ad70..439ebd0 100644 --- a/apps/DoseTool/DoseToolApplicationData.cpp +++ b/apps/DoseTool/DoseToolApplicationData.cpp @@ -1,92 +1,91 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) // @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) // @author $Author: hentsch $ (last changed by) */ #include "DoseToolApplicationData.h" #include "DoseToolCmdLineParser.h" namespace rttb { namespace apps { namespace doseTool { ApplicationData:: ApplicationData() { this->reset(); } void ApplicationData:: reset() { _doseFileName = ""; _structFileName = ""; _structNameRegex = ""; _doseStatisticOutputFileName = ""; _computeComplexDoseStatistics = false; _allowSelfIntersection = false; - _structIndices.clear(); _structNames.clear(); _prescribedDose = 1.0; _multipleStructsMode = false; _computeDVH = false; _computeDoseStatistics = false; } void populateAppData(boost::shared_ptr argParser, ApplicationData& appData) { appData._doseFileName = argParser->get(argParser->OPTION_DOSE_FILE); appData._doseLoadStyle = argParser->get > (argParser->OPTION_DOSE_LOAD_STYLE); appData._structFileName = argParser->get(argParser->OPTION_STRUCT_FILE); appData._structLoadStyle = argParser->get > (argParser->OPTION_STRUCT_LOAD_STYLE); appData._structNameRegex = argParser->get(argParser->OPTION_STRUCT_NAME); appData._multipleStructsMode = argParser->isSet(argParser->OPTION_MULTIPLE_STRUCTS_MODE); if (argParser->isSet(argParser->OPTION_DOSE_STATISTICS)) { appData._computeDoseStatistics = true; appData._doseStatisticOutputFileName = argParser->get (argParser->OPTION_DOSE_STATISTICS); appData._computeComplexDoseStatistics = argParser->isSet(argParser->OPTION_COMPLEX_STATISTICS); appData._allowSelfIntersection = argParser->isSet(argParser->OPTION_ALLOW_SELF_INTERSECTION_STRUCT); } if (argParser->isSet(argParser->OPTION_DVH)) { appData._computeDVH = true; appData._dvhOutputFilename = argParser->get(argParser->OPTION_DVH); } if (argParser->isSet(argParser->OPTION_DOSE_STATISTICS) && argParser->isSet(argParser->OPTION_PRESCRIBED_DOSE)) { appData._prescribedDose = argParser->get(argParser->OPTION_PRESCRIBED_DOSE); } } } } } diff --git a/apps/DoseTool/DoseToolApplicationData.h b/apps/DoseTool/DoseToolApplicationData.h index 6e241c3..945c80d 100644 --- a/apps/DoseTool/DoseToolApplicationData.h +++ b/apps/DoseTool/DoseToolApplicationData.h @@ -1,78 +1,77 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) // @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) // @author $Author: hentsch $ (last changed by) */ #ifndef __DOSETOOL_APPLICATION_DATA_H #define __DOSETOOL_APPLICATION_DATA_H #include #include "rttbDoseAccessorInterface.h" #include "rttbStructureSetGeneratorInterface.h" namespace rttb { namespace apps { namespace doseTool { class DoseToolCmdLineParser; /*! @class ApplicationData @brief Class for storing all relevant variables needed in DoseTool */ class ApplicationData { public: /**Vector of arguments used to specify the loading style (always the first argument) * and, if needed, additional arguments for the specified loading style. */ typedef std::vector LoadingStyleArgType; core::DoseAccessorInterface::DoseAccessorPointer _dose; core::StructureSetGeneratorInterface::StructureSetPointer _struct; std::string _structNameRegex; - std::vector _structIndices; std::vector _structNames; std::string _doseFileName; std::string _structFileName; LoadingStyleArgType _doseLoadStyle; LoadingStyleArgType _structLoadStyle; bool _computeComplexDoseStatistics; DoseTypeGy _prescribedDose; std::string _doseStatisticOutputFileName; bool _allowSelfIntersection; bool _multipleStructsMode; bool _computeDVH; bool _computeDoseStatistics; std::string _dvhOutputFilename; /*! @brief Resets the variables. _prescribedDose is set to 1.0 because it produces no exception then (as it is not needed). Consistency checks are done in DoseToolCmdLineParser::validateInput() */ void reset(); ApplicationData(); }; /*! @brief Reads the necessary arguments from the DoseToolCmdLineParser and writes them in the respective variables of ApplicationData. */ void populateAppData(boost::shared_ptr argParser, ApplicationData& appData); } } } #endif diff --git a/apps/DoseTool/DoseToolHelper.cpp b/apps/DoseTool/DoseToolHelper.cpp index 192c718..000f454 100644 --- a/apps/DoseTool/DoseToolHelper.cpp +++ b/apps/DoseTool/DoseToolHelper.cpp @@ -1,253 +1,245 @@ // ----------------------------------------------------------------------- // 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: 1374 $ (last changed revision) // @date $Date: 2016-05-30 14:15:42 +0200 (Mo, 30 Mai 2016) $ (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 "boost/property_tree/xml_parser.hpp" #include "boost/filesystem.hpp" #include "DoseToolApplicationData.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbDoseStatistics.h" #include "rttbDVH.h" #include "rttbDVHCalculator.h" #include "rttbDVHXMLFileWriter.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbDoseStatisticsXMLWriter.h" -#include "rttbVOIindexIdentifier.h" std::vector rttb::apps::doseTool::generateMasks( rttb::apps::doseTool::ApplicationData& appData) { std::vector maskAccessorPtrVector; if (appData._structLoadStyle.front() == "itk") { maskAccessorPtrVector.push_back(rttb::io::itk::ITKImageFileMaskAccessorGenerator( appData._structFileName).generateMaskAccessor()); appData._structNames.push_back(appData._structNameRegex); } else { - auto foundIndices = rttb::masks::VOIindexIdentifier::getIndicesByVoiRegex( - appData._struct, - appData._structNameRegex); - std::vector relevantIndices; - - if (appData._multipleStructsMode) - { - relevantIndices = foundIndices; - } - else - { - if (!foundIndices.empty()) - { - relevantIndices.push_back(foundIndices.front()); - } - } - - appData._structIndices = relevantIndices; - - bool strict = !appData._allowSelfIntersection; - - for (size_t i = 0; i < appData._structIndices.size(); i++) - { - maskAccessorPtrVector.emplace_back(boost::make_shared - (appData._struct->getStructure(appData._structIndices.at(i)), appData._dose->getGeometricInfo(), - strict)); - maskAccessorPtrVector.at(i)->updateMask(); - appData._structNames.push_back(appData._struct->getStructure(appData._structIndices.at( - i))->getLabel()); - } + if (appData._struct->getNumberOfStructures() > 0) { + //default behavior: read only first struct that matches the regex + unsigned int maxIterationCount = 1; + + //only if specified: read all structs that matches the regex + if (appData._multipleStructsMode) + { + maxIterationCount = appData._struct->getNumberOfStructures(); + } + + bool strict = !appData._allowSelfIntersection; + + for (size_t i = 0; i < maxIterationCount; i++) + { + maskAccessorPtrVector.emplace_back(boost::make_shared + (appData._struct->getStructure(i), appData._dose->getGeometricInfo(), strict)); + maskAccessorPtrVector.at(i)->updateMask(); + appData._structNames.push_back(appData._struct->getStructure(i)->getLabel()); + } + } + else { + std::cout << "no structures in structure set!" << std::endl; + } } return maskAccessorPtrVector; } 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 calculateDoseStatistics( rttb::core::DoseIteratorInterface::DoseIteratorPointer doseIterator, bool calculateComplexDoseStatistics, rttb::DoseTypeGy prescribedDose) { rttb::algorithms::DoseStatisticsCalculator doseStatsCalculator(doseIterator); if (calculateComplexDoseStatistics) { return doseStatsCalculator.calculateDoseStatistics(prescribedDose); } else { return doseStatsCalculator.calculateDoseStatistics(); } } rttb::core::DVH::DVHPointer calculateDVH( rttb::core::DoseIteratorInterface::DoseIteratorPointer doseIterator, rttb::IDType structUID, rttb::IDType doseUID) { rttb::core::DVHCalculator calc(doseIterator, structUID, doseUID); rttb::core::DVH::DVHPointer dvh = calc.generateDVH(); return dvh; } std::string rttb::apps::doseTool::assembleFilenameWithStruct(const std::string& originalFilename, const std::string& structName) { boost::filesystem::path originalFile(originalFilename); std::string newFilename = originalFile.stem().string() + "_" + structName + originalFile.extension().string(); boost::filesystem::path newFile(originalFile.parent_path() / newFilename); return newFile.string(); } /*! @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( rttb::algorithms::DoseStatistics::DoseStatisticsPointer statistics, const std::string& filename, const std::string& structName, 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", structName); 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(filename, reorderedTree, std::locale(), boost::property_tree::xml_writer_make_settings('\t', 1)); } void writeDVHFile(rttb::core::DVH::DVHPointer dvh, const std::string& filename) { rttb::DVHType typeCum = { rttb::DVHType::Cumulative }; rttb::io::other::DVHXMLFileWriter dvhWriter(filename, typeCum); dvhWriter.writeDVH(dvh); } void rttb::apps::doseTool::processData(rttb::apps::doseTool::ApplicationData& appData) { std::cout << std::endl << "generating masks... "; std::vector maskAccessorPtrVector = generateMasks( appData); std::cout << "done." << std::endl; for (size_t i = 0; i < maskAccessorPtrVector.size(); i++) { core::DoseIteratorInterface::DoseIteratorPointer spDoseIterator(generateMaskedDoseIterator( maskAccessorPtrVector.at(i), appData._dose)); if (appData._computeDoseStatistics) { std::cout << std::endl << "computing dose statistics... "; algorithms::DoseStatistics::DoseStatisticsPointer statistics = calculateDoseStatistics( spDoseIterator, appData._computeComplexDoseStatistics, appData._prescribedDose); std::cout << "done." << std::endl; std::cout << std::endl << "writing dose statistics to file... "; std::string outputFilename; if (appData._multipleStructsMode) { outputFilename = assembleFilenameWithStruct(appData._doseStatisticOutputFileName, appData._structNames.at(i)); } else { outputFilename = appData._doseStatisticOutputFileName; } writeDoseStatisticsFile(statistics, outputFilename, appData._structNames.at(i), appData); std::cout << "done." << std::endl; } if (appData._computeDVH) { std::cout << std::endl << "computing DVH... "; rttb::IDType structUID; rttb::IDType doseUID; //Generate random UID if (appData._structLoadStyle.front() == "itk"){ structUID = "struct42"; doseUID = "dose42"; } else { structUID = appData._struct->getUID(); doseUID = appData._dose->getUID(); } core::DVH::DVHPointer dvh = calculateDVH(spDoseIterator, structUID, doseUID); std::cout << "done." << std::endl; std::cout << std::endl << "writing DVH to file... "; std::string outputFilename; if (appData._multipleStructsMode) { outputFilename = assembleFilenameWithStruct(appData._dvhOutputFilename, appData._structNames.at(i)); } else { outputFilename = appData._dvhOutputFilename; } writeDVHFile(dvh, outputFilename); std::cout << "done." << std::endl; } } } diff --git a/apps/VoxelizerTool/CMakeLists.txt b/apps/VoxelizerTool/CMakeLists.txt index 9c99444..fba2b52 100644 --- a/apps/VoxelizerTool/CMakeLists.txt +++ b/apps/VoxelizerTool/CMakeLists.txt @@ -1,4 +1,4 @@ -MESSAGE (STATUS "generating app: VoxelizerTool - voxelize RTSRUCT files") +MESSAGE (STATUS "generating app: VoxelizerTool - voxelize DICOM RTSTRUCT files") SET(RTTB_Boost_ADDITIONAL_COMPONENT program_options) -RTTB_CREATE_APPLICATION(VoxelizerTool DEPENDS RTTBBoostMask RTTBMasks RTTBCore RTTBUtilsIO PACKAGE_DEPENDS ArgumentParsingLib ITK BoostBinaries) +RTTB_CREATE_APPLICATION(VoxelizerTool DEPENDS RTTBBoostMask RTTBCore RTTBUtilsIO PACKAGE_DEPENDS ArgumentParsingLib ITK BoostBinaries) diff --git a/apps/VoxelizerTool/VoxelizerTool.cpp b/apps/VoxelizerTool/VoxelizerTool.cpp index 3b9f7ba..9e70d48 100644 --- a/apps/VoxelizerTool/VoxelizerTool.cpp +++ b/apps/VoxelizerTool/VoxelizerTool.cpp @@ -1,147 +1,149 @@ // ----------------------------------------------------------------------- // 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: 1390 $ (last changed revision) // @date $Date: 2016-07-13 09:57:44 +0200 (Mi, 13 Jul 2016) $ (last change date) // @author $Author: strubel $ (last changed by) */ #include #include "VoxelizerToolHelper.h" #include "VoxelizerToolCmdLineParser.h" #include "VoxelizerToolApplicationData.h" #include "rttbDoseLoader.cpp" #include "rttbStructLoader.cpp" int main(int argc, const char** argv) { rttb::apps::voxelizerTool::ApplicationData appData; const std::string appCategory = "RT-Toolbox App"; const std::string appName = "VoxelizerTool"; const std::string appDesc = "An App to voxelize RT structures in a reference image."; const std::string appContributor = "SIDT@DKFZ"; const std::string appVersion = RTTB_FULL_VERSION_STRING; boost::shared_ptr argParser; try { argParser = boost::make_shared(argc, argv, appName, appVersion, appDesc, appContributor, appCategory); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return 5; } // This is vital. The application needs to exit if the "help" or "version" parameter is set // because this means the other parameters won't be parsed. if (argParser->isSet(argParser->OPTION_HELP) || argParser->isSet(argParser->OPTION_VERSION) || argParser->isSet(argParser->OPTION_XML)) { return 0; } rttb::apps::voxelizerTool::populateAppData(argParser, appData); std::cout << std::endl << "*******************************************" << std::endl; std::cout << "Struct file: " << appData._structFile << std::endl; std::cout << "Reference Image: " << appData._referenceFile << std::endl; std::cout << "Output file: " << appData._outputFilename << std::endl; std::cout << "Struct regex: " << appData._regEx << std::endl; std::cout << "Add structures: " << appData._addStructures << std::endl; std::cout << "Multiple Struct: " << appData._multipleStructs << std::endl; - std::cout << "No Strict voxelization: " << appData._noStrictVoxelization << std::endl << std::endl; + std::cout << "Strict voxelization: " << !appData._noStrictVoxelization << std::endl << std::endl; std::cout << "reading reference and structure file..." << std::endl; try { appData._dose = rttb::io::utils::loadDose(appData._referenceFile, appData._referenceFileLoadStyle); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (...) { std::cerr << "Error!!! unknown error while reading input dose image." << std::endl; return 2; } try { appData._struct = rttb::io::utils::loadStruct(appData._structFile, appData._structFileLoadStyle, appData._regEx); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (...) { std::cerr << "Error!!! unknown error while reading input struct image." << std::endl; return 2; } + std::cout << "done." << std::endl; + try { rttb::apps::voxelizerTool::processData(appData); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error while doing voxelization!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (itk::ExceptionObject& err) { std::cerr << "ExceptionObject caught !" << std::endl; std::cerr << err << std::endl; return 3; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 3; } catch (...) { std::cerr << "Error!!! unknown error while doing voxelization." << std::endl; return 3; } return 0; } diff --git a/apps/VoxelizerTool/VoxelizerToolHelper.cpp b/apps/VoxelizerTool/VoxelizerToolHelper.cpp index 806e188..5eda333 100644 --- a/apps/VoxelizerTool/VoxelizerToolHelper.cpp +++ b/apps/VoxelizerTool/VoxelizerToolHelper.cpp @@ -1,250 +1,227 @@ // ----------------------------------------------------------------------- // 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: 1127 $ (last changed revision) // @date $Date: 2015-10-01 13:33:33 +0200 (Do, 01 Okt 2015) $ (last change date) // @author $Author: hentsch $ (last changed by) */ #include #include "rttbBoostMaskAccessor.h" #include "itkMacro.h" #include "VoxelizerToolHelper.h" #include "VoxelizerToolApplicationData.h" #include "rttbITKImageMaskAccessorConverter.h" #include "rttbImageWriter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkAddImageFilter.h" -#include "rttbVOIindexIdentifier.h" - #include #include #include #include "rttbDicomFileStructureSetGenerator.h" void rttb::apps::voxelizerTool::removeSpecialCharacters(std::string& label) { //Replace / to avoid problems with directories (struct "Magen/DD" --> Magen/DD.mhd), delete trailing . to avoid filenames with two trailing points (Niere re. --> Niere re..mhd) while (label.find("/") != std::string::npos) { label.replace(label.find("/"), 1, "_"); } if (*label.rbegin() == '.') { label.replace(label.size() - 1, 1, ""); } } std::string rttb::apps::voxelizerTool::getFilenameWithoutEnding(const std::string& outfilename) { boost::filesystem::path p(outfilename); return p.replace_extension("").string(); } std::string rttb::apps::voxelizerTool::getFileEnding(const std::string& outfilename) { boost::filesystem::path p(outfilename); return p.extension().string(); } rttb::core::MaskAccessorInterface::MaskAccessorPointer rttb::apps::voxelizerTool::createMask( - rttb::core::DoseAccessorInterface::DoseAccessorPointer& doseAccessorPtr, - rttb::core::StructureSetGeneratorInterface::StructureSetPointer& structureSetPtr, - bool strict, unsigned int indexOfStructure) + rttb::core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr, + rttb::core::Structure::StructTypePointer structurePtr, + bool strict) { rttb::core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr; - if (doseAccessorPtr != nullptr && structureSetPtr != nullptr) + if (doseAccessorPtr != nullptr && structurePtr != nullptr) { maskAccessorPtr = boost::make_shared - (structureSetPtr->getStructure(indexOfStructure), doseAccessorPtr->getGeometricInfo(), + (structurePtr, doseAccessorPtr->getGeometricInfo(), strict); maskAccessorPtr->updateMask(); } return maskAccessorPtr; } -void rttb::apps::voxelizerTool::writeMaskToFile(std::vector& maskVector, +void rttb::apps::voxelizerTool::writeMaskToFile(std::vector maskVector, const std::string& outputFileName, bool voxelization) { if (!maskVector.empty()) { io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer itkImage; if (maskVector.size() > 1) { itkImage = addMultipleStructsToImage(maskVector); } else { io::itk::ITKImageMaskAccessorConverter maskAccessorConverter(maskVector.at(0)); maskAccessorConverter.process(); itkImage = maskAccessorConverter.getITKImage(); } if (voxelization) { itkImage = applyThresholdFilter(itkImage); } io::itk::ImageWriter writer(outputFileName, itkImage); writer.writeFile(); } } rttb::io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer rttb::apps::voxelizerTool::addMultipleStructsToImage( - std::vector& maskVector) + std::vector maskVector) { std::vector listOfITKImages; for (const auto & i : maskVector) { io::itk::ITKImageMaskAccessorConverter maskAccessorConverter(i); maskAccessorConverter.process(); listOfITKImages.push_back(maskAccessorConverter.getITKImage()); } itk::AddImageFilter , itk::Image>::Pointer addFilter = itk::AddImageFilter , itk::Image>::New(); io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer filterResult; for (int k = 1; k < listOfITKImages.size(); k++) { if (k == 1) { addFilter->SetInput1(listOfITKImages.at(0)); } else { addFilter->SetInput1(filterResult); } addFilter->SetInput2(listOfITKImages.at(k)); addFilter->Update(); filterResult = addFilter->GetOutput(); } - io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer filterResultConst(filterResult); - return filterResultConst; + return filterResult.GetPointer(); } rttb::io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer rttb::apps::voxelizerTool::applyThresholdFilter( - io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer& itkImage) + io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer itkImage) { itk::BinaryThresholdImageFilter< itk::Image, itk::Image >::Pointer filter = itk::BinaryThresholdImageFilter< itk::Image, itk::Image >::New(); filter->SetInput(itkImage); filter->SetLowerThreshold(0.5); filter->SetUpperThreshold(1.0); filter->SetInsideValue(1.0); filter->Update(); return filter->GetOutput(); } -void rttb::apps::voxelizerTool::writeITKImageToFile(io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer& itkImage, - const std::string& outputfilename, bool useCompression) -{ - itk::ImageFileWriter< itk::Image >::Pointer writer = - itk::ImageFileWriter< itk::Image >::New(); - writer->SetFileName(outputfilename); - writer->SetUseCompression(useCompression); - writer->SetInput(itkImage); - - writer->Update(); -} - void rttb::apps::voxelizerTool::processData(rttb::apps::voxelizerTool::ApplicationData& appData) { - - std::cout << "done." << std::endl; - - std::cout << "searching for structs..."; - - std::vector listOfCorrectElements, indexOfCorrectElements; - - indexOfCorrectElements = rttb::masks::VOIindexIdentifier::getIndicesByVoiRegex(appData._struct, appData._regEx); - - std::copy(indexOfCorrectElements.begin(), indexOfCorrectElements.end(), - std::back_inserter(listOfCorrectElements)); - - std::cout << "done." << std::endl; - - if (!listOfCorrectElements.empty()) + if (appData._struct->getNumberOfStructures()>0) { std::vector maskVector; if (appData._addStructures) { - for (unsigned long listOfCorrectElement : listOfCorrectElements) + for (size_t i=0; igetNumberOfStructures(); i++ ) { - maskVector.push_back(createMask(appData._dose, appData._struct, - !appData._noStrictVoxelization, listOfCorrectElement)); + std::cout << "creating mask #" << i << "..."; + maskVector.push_back(createMask(appData._dose, appData._struct->getStructure(i), + !appData._noStrictVoxelization)); + std::cout << "done" << std::endl; } - + std::cout << "writing mask to file..."; writeMaskToFile(maskVector, appData._outputFilename, appData._binaryVoxelization); - + std::cout << "done" << std::endl; } else { + //default behavior: read only first struct that matches the regex unsigned int maxIterationCount = 1; + //only if specified: read all structs that matches the regex if (appData._multipleStructs) { - maxIterationCount = listOfCorrectElements.size(); + maxIterationCount = appData._struct->getNumberOfStructures(); } - for (unsigned int i = 0; i < maxIterationCount; i++) + for (size_t i = 0; igetStructure(i), + !appData._noStrictVoxelization); std::cout << "done" << std::endl; - std::string labelOfInterest = rttb::masks::VOIindexIdentifier::getVoiNameByIndex(appData._struct, i); + std::string labelOfInterest = appData._struct->getStructure(i)->getLabel(); removeSpecialCharacters(labelOfInterest); std::string outputName = appData._outputFilename; if (appData._multipleStructs) { std::string fileName = getFilenameWithoutEnding( appData._outputFilename); std::string fileEnding = getFileEnding(appData._outputFilename); outputName = fileName + "_" + labelOfInterest + fileEnding; } std::vector currenMaskVector{ currentMask }; + std::cout << "writing mask #" << i << " to file..."; writeMaskToFile(currenMaskVector, outputName, appData._binaryVoxelization); + std::cout << "done" << std::endl; } } } else { std::cout << "No struct found" << std::endl; } } \ No newline at end of file diff --git a/apps/VoxelizerTool/VoxelizerToolHelper.h b/apps/VoxelizerTool/VoxelizerToolHelper.h index 61c770c..429046e 100644 --- a/apps/VoxelizerTool/VoxelizerToolHelper.h +++ b/apps/VoxelizerTool/VoxelizerToolHelper.h @@ -1,71 +1,69 @@ // ----------------------------------------------------------------------- // 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: 1127 $ (last changed revision) // @date $Date: 2015-10-01 13:33:33 +0200 (Do, 01 Okt 2015) $ (last change date) // @author $Author: hentsch $ (last changed by) */ #include #include -#include "rttbStructureSetGeneratorInterface.h" +#include "rttbStructure.h" #include "rttbMaskAccessorInterface.h" #include "rttbITKImageMaskAccessor.h" #include "rttbDoseAccessorInterface.h" namespace rttb { namespace apps { namespace voxelizerTool { class ApplicationData; void processData(ApplicationData& appData); /**@brief Search the label with the position from index @return a label from the list as string */ void removeSpecialCharacters(std::string& label); /**@brief create a mask with _rtStructureSet and _doseAccessor object. @return a mask object */ core::MaskAccessorInterface::MaskAccessorPointer createMask( - core::DoseAccessorInterface::DoseAccessorPointer& doseAccessorPtr, - core::StructureSetGeneratorInterface::StructureSetPointer& structureSetPtr, - bool strict, unsigned int indexOfStructure); + core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr, + rttb::core::Structure::StructTypePointer structurePtr, + bool strict); /**@brief write the mask into the outputfile @param Outputfilename */ - void writeMaskToFile(std::vector& maskVector, + void writeMaskToFile(std::vector maskVector, const std::string& outputFileName, bool voxelization); io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer addMultipleStructsToImage( - std::vector& maskVector); + std::vector maskVector); io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer applyThresholdFilter( - io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer& itkImage); - void writeITKImageToFile(io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer& itkImage, - const std::string& outputfilename, bool useCompression); + io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer itkImage); std::string getFilenameWithoutEnding(const std::string& outfilename); std::string getFileEnding(const std::string& outfilename); } } } \ No newline at end of file diff --git a/code/masks/files.cmake b/code/masks/files.cmake index 370758b..0cc43df 100644 --- a/code/masks/files.cmake +++ b/code/masks/files.cmake @@ -1,9 +1,7 @@ SET(CPP_FILES rttbGenericMutableMaskAccessor.cpp - rttbVOIindexIdentifier.cpp ) SET(H_FILES rttbGenericMutableMaskAccessor.h - rttbVOIindexIdentifier.h ) diff --git a/code/masks/rttbVOIindexIdentifier.cpp b/code/masks/rttbVOIindexIdentifier.cpp deleted file mode 100644 index 9c998c9..0000000 --- a/code/masks/rttbVOIindexIdentifier.cpp +++ /dev/null @@ -1,100 +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: -// @date $Date: -// @author $Author: -*/ - - -#include "rttbVOIindexIdentifier.h" - -#include - -#include "rttbExceptionMacros.h" - - - -namespace rttb -{ - namespace masks - { - - const std::vector VOIindexIdentifier::getIndicesByVoiRegex( - StructSetTypePointer spStructSet, - const std::string& nameAsRegEx) - { - if (spStructSet == nullptr) - { - rttbDefaultExceptionStaticMacro("spStructSet is nullptr"); - } - - std::vector resultVOiIndices; - std::regex e(nameAsRegEx); - - for (size_t i = 0; i < spStructSet->getNumberOfStructures(); i++) - { - std::string s = spStructSet->getStructure(i)->getLabel(); - - if (std::regex_match(s, e)) - { - resultVOiIndices.push_back(i); - } - } - - return resultVOiIndices; - } - - - const unsigned int VOIindexIdentifier::getIndexByVoiName(StructSetTypePointer spStructSet, - const std::string& name) - { - if (spStructSet == nullptr) - { - rttbDefaultExceptionStaticMacro("spStructSet is nullptr"); - } - - for (unsigned int i = 0; i < spStructSet->getNumberOfStructures(); i++) - { - if (spStructSet->getStructure(i)->getLabel() == name) - { - return i; - } - } - - rttbDefaultExceptionStaticMacro("no VOI was found with the given name"); - } - - - - const std::string VOIindexIdentifier::getVoiNameByIndex(StructSetTypePointer spStructSet, - unsigned int index) - { - if (spStructSet == nullptr) - { - rttbDefaultExceptionStaticMacro("spStructSet is nullptr!"); - } - - if (index >= spStructSet->getNumberOfStructures()) - { - rttbDefaultExceptionStaticMacro("invalid index, voiLabelList out of range"); - } - - return spStructSet->getStructure(index)->getLabel(); - } - } -} - diff --git a/code/masks/rttbVOIindexIdentifier.h b/code/masks/rttbVOIindexIdentifier.h deleted file mode 100644 index 00ab200..0000000 --- a/code/masks/rttbVOIindexIdentifier.h +++ /dev/null @@ -1,90 +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: -// @date $Date: -// @author $Author: -*/ - -#ifndef __VOI_INDEX_IDENTIFIER_H -#define __VOI_INDEX_IDENTIFIER_H - -#include "rttbStructureSet.h" -#include "rttbStructure.h" - -#include "RTTBMasksExports.h" - -namespace rttb -{ - namespace masks - { - /*! @class VOIindexIdentifier - @brief Collection of functions for the identification of structs in RTSTRUCT files. - */ - class RTTBMasks_EXPORT VOIindexIdentifier - { - - public: - using Pointer = ::boost::shared_ptr; - using StructSetType = ::rttb::core::StructureSet; - using StructSetTypePointer = ::boost::shared_ptr; - using StructType = ::rttb::core::Structure; - - public: - - VOIindexIdentifier() = default; - virtual ~VOIindexIdentifier() = default; - - - /*!@brief get indices of all VOI that agree with the regex - * @details if the regex does not agree with any VOI, the returning vector is empty. - * @pre spStructSet must point to a valid structure set. - * @param spStructSet Pointer to the structure set that should be checked for the named VOI. - * @param name Regular expression of the VOI - * @exception ::rttb::core::Exception on invalid spStructSet - * @return a vector of all found indices */ - static const std::vector getIndicesByVoiRegex(StructSetTypePointer spStructSet, - const std::string& name); - - /*!@brief get the index of the corresponding VOI name - * @details only if the exact name is found, the index will be given. - * @pre name must contain a valid VOI name - * @pre spStructSet must point to a valid structure set. - * @param spStructSet Pointer to the structure set that should be checked for the named VOI. - * @param name Name of the VOI - * @exception ::rttb::core::Exception on invalid spStructSet - * @exception ::rttb::core::Exception on invalid name (not found in structure set) - * @return the index */ - static const unsigned int getIndexByVoiName(StructSetTypePointer spStructSet, - const std::string& name); - - /*!@brief get the VOI of the corresponding index - * @pre index must specify a valid index value - * @pre spStructSet must point to a valid structure set. - * @param spStructSet Pointer to the structure set that should be checked for the named VOI. - * @param index Index of the VOI - * @exception ::rttb::core::Exception on invalid spStructSet or index>maxLabelIndex - * @return voi name */ - static const std::string getVoiNameByIndex(StructSetTypePointer spStructSet, - unsigned int index); - - - }; - - } -} - -#endif diff --git a/testing/algorithms/CMakeLists.txt b/testing/algorithms/CMakeLists.txt index 5f448a0..bc7bef1 100644 --- a/testing/algorithms/CMakeLists.txt +++ b/testing/algorithms/CMakeLists.txt @@ -1,20 +1,20 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(ALGORITHMS_TESTS ${EXECUTABLE_OUTPUT_PATH}/rttbAlgorithmsTests) SET(ALGORITHMS_HEADER_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbAlgorithmsHeaderTest) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- ADD_TEST(DoseStatisticsTest ${ALGORITHMS_TESTS} DoseStatisticsTest) ADD_TEST(ArithmeticTest ${ALGORITHMS_TESTS} ArithmeticTest) ADD_TEST(DoseStatisticsCalculatorTest ${ALGORITHMS_TESTS} DoseStatisticsCalculatorTest "${TEST_DATA_ROOT}/DoseStatistics/XML/dicom_heartComplex.xml" "${TEST_DATA_ROOT}/Dose/DICOM/dicompylerTestDose.dcm" "${TEST_DATA_ROOT}/StructureSet/DICOM/rtss.dcm") ADD_TEST(BinaryFunctorAccessorTest ${ALGORITHMS_TESTS} BinaryFunctorAccessorTest "${TEST_DATA_ROOT}/Dose/DICOM/ConstantTwo.dcm" "${TEST_DATA_ROOT}/Dose/DICOM/dicompylerTestDose.dcm") -RTTB_CREATE_TEST_MODULE(rttbAlgorithms DEPENDS RTTBAlgorithms RTTBMasks RTTBBoostMask RTTBDicomIO PACKAGE_DEPENDS Boost Litmus RTTBData DCMTK) +RTTB_CREATE_TEST_MODULE(rttbAlgorithms DEPENDS RTTBAlgorithms RTTBBoostMask RTTBDicomIO PACKAGE_DEPENDS Boost Litmus RTTBData DCMTK) diff --git a/testing/algorithms/DoseStatisticsCalculatorTest.cpp b/testing/algorithms/DoseStatisticsCalculatorTest.cpp index 108ec0f..e8d3627 100644 --- a/testing/algorithms/DoseStatisticsCalculatorTest.cpp +++ b/testing/algorithms/DoseStatisticsCalculatorTest.cpp @@ -1,393 +1,391 @@ // ----------------------------------------------------------------------- // 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 "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDoseIteratorInterface.h" #include "rttbNullPointerException.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include "rttbDataNotAvailableException.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" -#include "rttbVOIindexIdentifier.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "../io/other/CompareDoseStatistic.h" #include "../../code/io/other/rttbDoseStatisticsXMLReader.h" #include "../core/DummyDoseAccessor.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; typedef rttb::algorithms::DoseStatistics::ResultListPointer ResultListPointer; typedef rttb::algorithms::DoseStatistics::DoseStatisticsPointer DoseStatisticsPointer; /*! @brief DoseStatisticsCalculatorTest - test the API of DoseStatisticsCalculator 1) test constructors 2) test setDoseIterator 3) test calculateDoseSatistics 4) get statistical values */ int DoseStatisticsCalculatorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string referenceXMLFilename; std::string doseFilename, structFilename; boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); const std::vector* doseVals = spTestDoseAccessor->getDoseVector(); boost::shared_ptr spTestDoseIterator = boost::make_shared(spDoseAccessor); DoseIteratorPointer spDoseIterator(spTestDoseIterator); DoseIteratorPointer spDoseIteratorNull; if (argc > 3) { referenceXMLFilename = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; } //1) test constructors // the values cannot be accessed from outside, therefore correct default values are not tested CHECK_THROW_EXPLICIT(rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator( spDoseIteratorNull), core::NullPointerException); CHECK_NO_THROW(rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator)); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); //2) test setDoseIterator //3) test calculateDoseStatistics DoseStatisticsPointer theStatistics; //simple dose statistics CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics()); CHECK_EQUAL(theStatistics->getMinimumVoxelPositions()->empty(), false); CHECK_EQUAL(theStatistics->getMaximumVoxelPositions()->empty(), false); CHECK_EQUAL(theStatistics->getVx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getDx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getVx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMaxOHx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMOHx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMOCx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMinOCx().getAllValues().empty(), true); //check default values for computeComplexMeasures=true DoseStatisticsPointer theStatisticsDefault; myDoseStatsCalculator.setMultiThreading(true); CHECK_NO_THROW(theStatisticsDefault = myDoseStatsCalculator.calculateDoseStatistics(true)); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.02 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.05 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.1 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.9 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.95 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.98 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.02 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.05 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.1 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.9 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.95 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.98 * theStatisticsDefault->getVolume())); //check manually set reference dose and the default x values CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(100.0)); CHECK_THROW_EXPLICIT(theStatistics->getVx().getValue(0.1 * theStatistics->getMaximum()), core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getVx().getValue(0.1 * 100.0)); CHECK_NO_THROW(theStatistics->getDx().getValue(0.1 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getMOHx().getValue(0.95 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getMOCx().getValue(0.98 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getReferenceDose(), 100.0); //check manually set x values std::vector precomputeDoseValues, precomputeVolumeValues, additionalValues, faultyValues; precomputeDoseValues.push_back(0.01); precomputeDoseValues.push_back(0.02); precomputeDoseValues.push_back(0.05); precomputeVolumeValues.push_back(0.9); precomputeVolumeValues.push_back(0.95); precomputeVolumeValues.push_back(0.99); additionalValues.push_back(0.03); additionalValues.push_back(0.04); faultyValues.push_back(2); CHECK_THROW_EXPLICIT(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, faultyValues), core::InvalidParameterException); CHECK_THROW_EXPLICIT(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(faultyValues, precomputeVolumeValues), core::InvalidParameterException); CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, precomputeVolumeValues)); CHECK_NO_THROW(theStatistics->getVx().getValue(0.01 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getVx().getValue(0.02 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getVx().getValue(0.05 * theStatistics->getMaximum())); CHECK_THROW_EXPLICIT(theStatistics->getVx().getValue(0.03 * theStatistics->getMaximum()), core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.95 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.99 * theStatistics->getVolume())); CHECK_THROW_EXPLICIT(theStatistics->getDx().getValue(0.04 * theStatistics->getVolume()), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(myDoseStatsCalculator.addPrecomputeValues(faultyValues), core::InvalidParameterException); CHECK_NO_THROW(myDoseStatsCalculator.addPrecomputeValues(additionalValues)); CHECK_NO_THROW(myDoseStatsCalculator.recalculateDoseStatistics()); CHECK_NO_THROW(theStatistics->getVx().getValue(0.03 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.04 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getVx().getValue(0.02 * theStatistics->getMaximum()), theStatisticsDefault->getVx().getValue(0.02 * theStatistics->getMaximum())); CHECK_EQUAL(theStatistics->getVx().getValue(0.05 * theStatistics->getMaximum()), theStatisticsDefault->getVx().getValue(0.05 * theStatistics->getMaximum())); CHECK_EQUAL(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume()), theStatisticsDefault->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getDx().getValue(0.95 * theStatistics->getVolume()), theStatisticsDefault->getDx().getValue(0.95 * theStatistics->getVolume())); //check manually set reference dose and x values CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, precomputeVolumeValues, 100.0)); CHECK_THROW_EXPLICIT(theStatistics->getVx().getValue(0.01 * theStatistics->getMaximum()), core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getVx().getValue(0.01 * 100.0)); CHECK_NO_THROW(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getReferenceDose(), 100.0); //MOHx, MOCx, MaxOHx and MinOCx are computed analogous to Dx, they will not be checked. //4) get statistical values CHECK_EQUAL(theStatistics->getNumberOfVoxels(), doseVals->size()); //compute simple statistical values (min, mean, max, stddev) for comparison DoseStatisticType maximum = 0; DoseStatisticType minimum = 1000000; DoseStatisticType mean = 0; DoseStatisticType variance = 0; std::vector::const_iterator doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { if (maximum < *doseIt) { maximum = *doseIt; } if (minimum > *doseIt) { minimum = *doseIt; } mean += *doseIt; ++doseIt; } mean /= doseVals->size(); doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { variance += pow(*doseIt - mean, 2); ++doseIt; } variance /= doseVals->size(); DoseStatisticType stdDev = pow(variance, 0.5); //we have some precision problems here... double errorConstantLarger = 1e-2; CHECK_EQUAL(theStatistics->getMaximum(), maximum); CHECK_EQUAL(theStatistics->getMinimum(), minimum); CHECK_CLOSE(theStatistics->getMean(), mean, errorConstantLarger); CHECK_CLOSE(theStatistics->getStdDeviation(), stdDev, errorConstantLarger); CHECK_CLOSE(theStatistics->getVariance(), variance, errorConstantLarger); //check for complex doseStatistics (maximumPositions, minimumPositions, Vx, Dx, MOHx, MOCx, MAXOHx, MinOCx) unsigned int nMax = 0, nMin = 0; doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { if (*doseIt == theStatistics->getMaximum()) { nMax++; } if (*doseIt == theStatistics->getMinimum()) { nMin++; } ++doseIt; } //only 100 positions are stored if (nMax > 100) { nMax = 100; } if (nMin > 100) { nMin = 100; } auto maximaPositions = theStatistics->getMaximumVoxelPositions(); auto minimaPositions = theStatistics->getMinimumVoxelPositions(); CHECK_EQUAL(maximaPositions->size(), nMax); CHECK_EQUAL(minimaPositions->size(), nMin); for (auto maximaPositionsIterator = std::begin(*maximaPositions); maximaPositionsIterator != std::end(*maximaPositions); ++maximaPositionsIterator) { CHECK_EQUAL(maximaPositionsIterator->first, theStatistics->getMaximum()); } for (auto minimaPositionsIterator = std::begin(*minimaPositions); minimaPositionsIterator != std::end(*minimaPositions); ++minimaPositionsIterator) { CHECK_EQUAL(minimaPositionsIterator->first, theStatistics->getMinimum()); } //generate specific example dose maximum = 9.5; minimum = 2.5; mean = 6; int sizeTemplate = 500; std::vector aDoseVector; for (int i = 0; i < sizeTemplate; i++) { aDoseVector.push_back(maximum); aDoseVector.push_back(minimum); } core::GeometricInfo geoInfo = spTestDoseAccessor->getGeometricInfo(); geoInfo.setNumRows(20); geoInfo.setNumColumns(10); geoInfo.setNumSlices(5); boost::shared_ptr spTestDoseAccessor2 = boost::make_shared(aDoseVector, geoInfo); DoseAccessorPointer spDoseAccessor2(spTestDoseAccessor2); boost::shared_ptr spTestDoseIterator2 = boost::make_shared(spDoseAccessor2); DoseIteratorPointer spDoseIterator2(spTestDoseIterator2); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator2(spDoseIterator2); DoseStatisticsPointer theStatistics3 = myDoseStatsCalculator2.calculateDoseStatistics(); CHECK_EQUAL(theStatistics3->getMaximum(), maximum); CHECK_EQUAL(theStatistics3->getMinimum(), minimum); CHECK_EQUAL(theStatistics3->getMean(), mean); maximaPositions = theStatistics3->getMaximumVoxelPositions(); minimaPositions = theStatistics3->getMinimumVoxelPositions(); CHECK_EQUAL(maximaPositions->empty(), false); CHECK_EQUAL(minimaPositions->empty(), false); for (auto maximaPositionsIterator = std::begin(*maximaPositions); maximaPositionsIterator != std::end(*maximaPositions); ++maximaPositionsIterator) { CHECK_EQUAL(maximaPositionsIterator->first, theStatistics3->getMaximum()); } for (auto minimaPositionsIterator = std::begin(*minimaPositions); minimaPositionsIterator != std::end(*minimaPositions); ++minimaPositionsIterator) { CHECK_EQUAL(minimaPositionsIterator->first, theStatistics3->getMinimum()); } // compare with actual XML io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator(doseFilename.c_str()); core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPointer(doseAccessorGenerator.generateDoseAccessor()); rttb::io::dicom::DicomFileStructureSetGenerator structAccessorGenerator(structFilename.c_str()); - core::StructureSetGeneratorInterface::StructureSetPointer structerSetGeneratorPointer = structAccessorGenerator.generateStructureSet(); - - std::vector foundIndices = rttb::masks::VOIindexIdentifier::getIndicesByVoiRegex( - structerSetGeneratorPointer, "Heart"); + structAccessorGenerator.setStructureLabelFilterActive(true); + structAccessorGenerator.setFilterRegEx("Heart"); + core::StructureSetGeneratorInterface::StructureSetPointer structureSetGeneratorPointer = structAccessorGenerator.generateStructureSet(); - CHECK_EQUAL(foundIndices.size(), 1); + CHECK_EQUAL(structureSetGeneratorPointer->getNumberOfStructures(), 1); core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPointer = boost::make_shared - (structerSetGeneratorPointer->getStructure(foundIndices.at(0)), doseAccessorPointer->getGeometricInfo(), true); + (structureSetGeneratorPointer->getStructure(0), doseAccessorPointer->getGeometricInfo(), true); maskAccessorPointer->updateMask(); boost::shared_ptr maskedDoseIterator = boost::make_shared(maskAccessorPointer, doseAccessorPointer); rttb::core::DoseIteratorInterface::DoseIteratorPointer doseIteratorPointer(maskedDoseIterator); rttb::algorithms::DoseStatisticsCalculator doseStatisticsCalculator(doseIteratorPointer); DoseStatisticsPointer doseStatisticsActual = doseStatisticsCalculator.calculateDoseStatistics(14.0); io::other::DoseStatisticsXMLReader readerDefaultExpected(referenceXMLFilename); auto doseStatisticsExpected = readerDefaultExpected.generateDoseStatistic(); CHECK(checkEqualDoseStatistic(doseStatisticsExpected, doseStatisticsActual)); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/masks/CMakeLists.txt b/testing/masks/CMakeLists.txt index 6891453..65db7d6 100644 --- a/testing/masks/CMakeLists.txt +++ b/testing/masks/CMakeLists.txt @@ -1,28 +1,12 @@ MESSAGE (STATUS "Process All Mask Tests...") #----------------------------------------------------------------------------- # Include sub directories #----------------------------------------------------------------------------- ADD_SUBDIRECTORY(boost) IF(BUILD_Masks_Legacy) ADD_SUBDIRECTORY(legacy) -ENDIF() - -#----------------------------------------------------------------------------- -# Setup the system information test. Write out some basic failsafe -# information in case the test doesn't run. -#----------------------------------------------------------------------------- - -SET(Masks_TESTS ${EXECUTABLE_OUTPUT_PATH}/rttbMasksTests) - -SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) - -#----------------------------------------------------------------------------- -ADD_TEST(VOIindexIdentifierTest ${Masks_TESTS} VOIindexIdentifierTest -"${TEST_DATA_ROOT}/StructureSet/DICOM/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" ) - - -RTTB_CREATE_TEST_MODULE(rttbMasks DEPENDS RTTBDicomIO RTTBMasks PACKAGE_DEPENDS Boost Litmus RTTBData DCMTK) \ No newline at end of file +ENDIF() \ No newline at end of file diff --git a/testing/masks/VOIindexIdentifierTest.cpp b/testing/masks/VOIindexIdentifierTest.cpp deleted file mode 100644 index f56e7ef..0000000 --- a/testing/masks/VOIindexIdentifierTest.cpp +++ /dev/null @@ -1,116 +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: -// @date $Date: -// @author $Author: -*/ - -// this file defines the rttbCoreTests for the test driver -// and all it expects is that you have a function called RegisterTests - -#include "litCheckMacros.h" - -#include "rttbBaseType.h" -#include "rttbDicomFileStructureSetGenerator.h" -#include "rttbInvalidParameterException.h" -#include "rttbVOIindexIdentifier.h" - -namespace rttb -{ - - namespace testing - { - - int VOIindexIdentifierTest(int argc, char* argv[]) - { - PREPARE_DEFAULT_TEST_REPORTING; - - typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; - - //ARGUMENTS: 1: structure file name - std::string RTSTRUCT_FILENAME; - - - if (argc > 1) - { - RTSTRUCT_FILENAME = argv[1]; - } - - StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( - RTSTRUCT_FILENAME.c_str()).generateStructureSet(); - - StructureSetPointer emptyPointer = StructureSetPointer(); - - CHECK_NO_THROW(::rttb::masks::VOIindexIdentifier testVOIindexId - = ::rttb::masks::VOIindexIdentifier()); - ::rttb::masks::VOIindexIdentifier testVOIindexId = ::rttb::masks::VOIindexIdentifier(); - - /* getIndexByVoiName */ - CHECK_THROW_EXPLICIT(testVOIindexId.getIndexByVoiName(emptyPointer, "Leber"), - ::rttb::core::Exception); - CHECK_THROW_EXPLICIT(testVOIindexId.getIndexByVoiName(rtStructureSet, "Invalid"), - ::rttb::core::Exception); - - unsigned int indexActual; - unsigned int indexExpected = 5; - - CHECK_NO_THROW(indexActual = testVOIindexId.getIndexByVoiName(rtStructureSet, "Leber")); - CHECK_EQUAL(indexActual, indexExpected); - - - /*getIndicesByVoiRegex*/ - CHECK_THROW_EXPLICIT(testVOIindexId.getIndicesByVoiRegex(emptyPointer, "Leber"), - ::rttb::core::Exception); - - std::vector vectorActual; - std::vector vectorExpected; - vectorExpected.push_back(5); - CHECK_NO_THROW(vectorActual = testVOIindexId.getIndicesByVoiRegex(rtStructureSet, "Leber")); - CHECK_EQUAL(vectorActual.size(), vectorExpected.size()); - CHECK_EQUAL(vectorActual.at(0), vectorExpected.at(0)); - - vectorExpected.clear(); - vectorExpected.push_back(2); - vectorExpected.push_back(3); - CHECK_NO_THROW(vectorActual = testVOIindexId.getIndicesByVoiRegex(rtStructureSet, "Niere.*")); - - CHECK_EQUAL(vectorActual.size(), vectorExpected.size()); - CHECK_EQUAL(vectorActual.at(0), vectorExpected.at(0)); - CHECK_EQUAL(vectorActual.at(1), vectorExpected.at(1)); - - CHECK_NO_THROW(vectorActual = testVOIindexId.getIndicesByVoiRegex(rtStructureSet, ".*")); - CHECK_EQUAL(vectorActual.size(), 10); - - for (size_t index = 0; index < vectorActual.size(); index++) - { - CHECK_EQUAL(vectorActual.at(index), index); - } - - /* getVoiNameByIndex */ - CHECK_THROW_EXPLICIT(testVOIindexId.getVoiNameByIndex(emptyPointer, 5), - ::rttb::core::Exception); - CHECK_THROW_EXPLICIT(testVOIindexId.getVoiNameByIndex(rtStructureSet, 20), ::rttb::core::Exception); - - CHECK_EQUAL(testVOIindexId.getVoiNameByIndex(rtStructureSet, 5), "Leber"); - - - RETURN_AND_REPORT_TEST_SUCCESS; - } - - }//testing -}//rttb - diff --git a/testing/masks/files.cmake b/testing/masks/files.cmake deleted file mode 100644 index b5c92ab..0000000 --- a/testing/masks/files.cmake +++ /dev/null @@ -1,7 +0,0 @@ -SET(CPP_FILES - VOIindexIdentifierTest.cpp - rttbMasksTests.cpp - ) - -SET(H_FILES -) diff --git a/testing/masks/rttbMasksTests.cpp b/testing/masks/rttbMasksTests.cpp deleted file mode 100644 index c13bce8..0000000 --- a/testing/masks/rttbMasksTests.cpp +++ /dev/null @@ -1,63 +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 -#if defined(_MSC_VER) -#pragma warning ( disable : 4786 ) -#endif - - -#include "litMultiTestsMain.h" - -namespace rttb -{ - namespace testing - { - - void registerTests() - { - LIT_REGISTER_TEST(VOIindexIdentifierTest); - } - } -} - -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; -}