diff --git a/testing/validation/CMakeLists.txt b/testing/validation/CMakeLists.txt index a117647..ff2c50f 100644 --- a/testing/validation/CMakeLists.txt +++ b/testing/validation/CMakeLists.txt @@ -1,28 +1,27 @@ #----------------------------------------------------------------------------- # 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/" -"${RTTBTesting_BINARY_DIR}/validation/1.3.6.1.4.1.2452.6.2037938358.1234393433.864109958.30410275/BoostMaskRedesign/") +"${TEST_DATA_ROOT}/DVH/XML/1.3.6.1.4.1.2452.6.2037938358.1234393433.864109958.30410275/BoostMask_LEGACY/" +"${RTTBTesting_BINARY_DIR}/validation/1.3.6.1.4.1.2452.6.2037938358.1234393433.864109958.30410275/BoostMask/") 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/" "${RTTBTesting_BINARY_DIR}/validation/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") +"${TEST_DATA_ROOT}/Mask/1.3.6.1.4.1.2452.6.2037938358.1234393433.864109958.30410275/OTBMask/") 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 index e8e5e28..9dac98e 100644 --- a/testing/validation/VoxelizationDVHComparisonTest.cpp +++ b/testing/validation/VoxelizationDVHComparisonTest.cpp @@ -1,181 +1,181 @@ // ----------------------------------------------------------------------- // 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"){ + if (voxelizationType == "Boost"){ 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_LEGACY_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]; + RTDVH_XML_BOOST_LEGACY_DIRECTORY = argv[4]; + RTDVH_XML_BOOST_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(); //create directory - boost::filesystem::create_directories(RTDVH_XML_BOOSTREDESIGN_DIRECTORY); + boost::filesystem::create_directories(RTDVH_XML_BOOST_DIRECTORY); //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 spMaskedDoseIteratorBoostRedesign = createMaskDoseIterator(rtStructureSet->getStructure(j), doseAccessor1, "Boost"); 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); + boost::filesystem::path dvhBoostFilename(RTDVH_XML_BOOST_LEGACY_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); + boost::filesystem::path dvhBoostRedesignFilename(RTDVH_XML_BOOST_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 << "with Boost_LEGACY voxelization: " << std::endl; std::cout << dvhBoost << std::endl; - std::cout << "with BoostRedesign voxelization: " << std::endl; + std::cout << "with Boost 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); + boost::filesystem::path dvhBoostRedesignDiffFilename(RTDVH_XML_BOOST_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 index f27e268..7229cd8 100644 --- a/testing/validation/VoxelizationValidationTest.cpp +++ b/testing/validation/VoxelizationValidationTest.cpp @@ -1,194 +1,160 @@ // ----------------------------------------------------------------------- // 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 - { + 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[]) - { + /*! @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]; - } + 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; + + if (argc > 4) + { + RTSTRUCT_FILENAME = argv[1]; + RTDOSE_FILENAME = argv[2]; + BoostMask_DIRNAME = argv[3]; + OTBMask_DIRNAME = argv[4]; + } //create directory - boost::filesystem::create_directories(BoostMaskRedesign_DIRNAME); + boost::filesystem::create_directories(BoostMask_DIRNAME); - /* read dicom-rt dose */ - io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); - DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); + /* 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(); + //create a vector of MaskAccessors (one for each structure) + StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( + RTSTRUCT_FILENAME.c_str()).generateStructureSet(); - if (rtStructureSet->getNumberOfStructures() > 0) - { + if (rtStructureSet->getNumberOfStructures() > 0) + { //do not compute structure "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; + 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()); + //create Boost MaskAccessor + clock_t startR(clock()); - MaskAccessorPointer boostMaskRPtr - = ::boost::make_shared - (rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); - CHECK_NO_THROW(boostMaskRPtr->updateMask()); + 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; + clock_t finishR(clock()); + std::cout << "Boost Mask Calculation: " << finishR - startR << " ms" << + std::endl; - rttb::io::itk::ITKImageMaskAccessorConverter itkConverterR(boostMaskRPtr); - CHECK(itkConverterR.process()); + rttb::io::itk::ITKImageMaskAccessorConverter itkConverterR(boostMaskRPtr); + CHECK(itkConverterR.process()); - boost::filesystem::path redesignFilename(BoostMaskRedesign_DIRNAME); + boost::filesystem::path redesignFilename(BoostMask_DIRNAME); redesignFilename /= boost::lexical_cast(j)+".nrrd"; rttb::io::itk::ImageWriter writerR(redesignFilename.string(), itkConverterR.getITKImage()); - CHECK(writerR.writeFile()); + CHECK(writerR.writeFile()); auto subtractedRedesignImage = subtractImages(otbMaskImage, itkConverterR.getITKImage()); - boost::filesystem::path subtractRedesignFilename(BoostMaskRedesign_DIRNAME); - subtractRedesignFilename /= boost::lexical_cast(j) + "_subtracted.nrrd"; + boost::filesystem::path subtractRedesignFilename(BoostMask_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++) - { - //do not compute the largest structure - if (j != 18){ - 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; - } + RETURN_AND_REPORT_TEST_SUCCESS; + } - }//testing + }//testing }//rttb diff --git a/testing/validation/files.cmake b/testing/validation/files.cmake index b489d59..891c3df 100644 --- a/testing/validation/files.cmake +++ b/testing/validation/files.cmake @@ -1,10 +1,10 @@ SET(CPP_FILES VoxelizationDVHComparisonTest.cpp VoxelizationValidationTest.cpp ../io/other/CompareDVH.cpp rttbValidationTests.cpp ) SET(H_FILES - ../io/other/CompareDVH.h + ../io/other/CompareDVH.h )