diff --git a/code/masks/rttbBoostMaskAccessor.cpp b/code/masks/rttbBoostMaskAccessor.cpp index e69de29..af0a77e 100644 --- a/code/masks/rttbBoostMaskAccessor.cpp +++ b/code/masks/rttbBoostMaskAccessor.cpp @@ -0,0 +1,163 @@ +// ----------------------------------------------------------------------- +// 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: 484 $ (last changed revision) +// @date $Date: 2014-03-26 16:16:16 +0100 (Mi, 26 Mrz 2014) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ + +#include "rttbBoostMaskAccessor.h" +#include "rttbMaskBoost.h" +#include "rttbMappingOutsideOfImageException.h" + +#include + +#include +#include +#include + +namespace rttb +{ + + namespace masks + { + + BoostMaskAccessor::BoostMaskAccessor(StructTypePointer aStructurePointer, GeometricInfoPtr aGeometricInfoPtr) + : _spStructure(aStructurePointer), _spGeoInfo(aGeometricInfoPtr) + { + _spRelevantVoxelVector = MaskVoxelListPointer(); + + //generate new structure set uid + boost::uuids::uuid id; + boost::uuids::random_generator generator; + id = generator(); + std::stringstream ss; + ss << id; + _maskUID = "BoostMask_" + ss.str(); + } + + + BoostMaskAccessor::~BoostMaskAccessor() + { + }; + + void BoostMaskAccessor::updateMask() + { + MaskVoxelList newRelevantVoxelVector; + + if (_spRelevantVoxelVector) + { + return; // already calculated + } + + + MaskBoost mask(_spGeoInfo , _spStructure); + + _spRelevantVoxelVector = mask.getRelevantVoxelVector(); + + return; + } + + BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector() + { + // if not already generated start voxelization here + updateMask(); + return _spRelevantVoxelVector; + } + + BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector(float lowerThreshold) + { + MaskVoxelListPointer filteredVoxelVectorPointer(new MaskVoxelList); + updateMask(); + // filter relevant voxels + BoostMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); + + while (it != _spRelevantVoxelVector->end()) + { + if ((*it).getRelevantVolumeFraction() > lowerThreshold) + { + filteredVoxelVectorPointer->push_back(*it); + } + + ++it; + } + + // if mask calculation was not successful this is empty! + return filteredVoxelVectorPointer; + } + + bool BoostMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const + { + //initialize return voxel + voxel.setRelevantVolumeFraction(0); + + //check if ID is valid + if (!_spGeoInfo->validID(aID)) + { + return false; + } + + //determine how a given voxel on the dose grid is masked + if (_spRelevantVoxelVector) + { + BoostMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); + + while (it != _spRelevantVoxelVector->end()) + { + if ((*it).getVoxelGridID() == aID) + { + voxel = (*it); + return true; + } + + ++it; + } + + //aID is not in mask + voxel.setRelevantVolumeFraction(0); + } + // returns false if mask was not calculated without triggering calculation (otherwise not const!) + else + { + return false; + } + + return false; + + } + + bool BoostMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const + { + //convert VoxelGridIndex3D to VoxelGridID + VoxelGridID aVoxelGridID; + + if (_spGeoInfo->convert(aIndex, aVoxelGridID)) + { + return getMaskAt(aVoxelGridID, voxel); + } + else + { + return false; + } + } + + const core::GeometricInfo& BoostMaskAccessor::getGeometricInfo() const + { + return *_spGeoInfo; + }; + + } +} \ No newline at end of file diff --git a/code/masks/rttbBoostMaskAccessor.h b/code/masks/rttbBoostMaskAccessor.h index e69de29..8a89941 100644 --- a/code/masks/rttbBoostMaskAccessor.h +++ b/code/masks/rttbBoostMaskAccessor.h @@ -0,0 +1,110 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 484 $ (last changed revision) +// @date $Date: 2014-03-26 16:16:16 +0100 (Mi, 26 Mrz 2014) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ +#ifndef __BOOST_MASK_ACCESSOR__H +#define __BOOST_MASK_ACCESSOR__H + +#include "rttbBaseType.h" +#include "rttbGeometricInfo.h" +#include "rttbMaskVoxel.h" +#include "rttbMaskBoost.h" +#include "rttbMaskAccessorInterface.h" +#include "rttbGenericDoseIterator.h" +#include "rttbStructure.h" + +#include + + +namespace rttb +{ + + namespace masks + { + /*! @class OTBMaskAccessor + * @brief Implementation of original toolbox voxelization by M. Hub. + */ + class BoostMaskAccessor: public core::MaskAccessorInterface + { + public: + typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; + typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; + + typedef core::Structure::StructTypePointer StructTypePointer; + typedef boost::shared_ptr GeometricInfoPtr; + + private: + + GeometricInfoPtr _spGeoInfo; + + /*! vector containing list of mask voxels*/ + MaskVoxelListPointer _spRelevantVoxelVector; + + StructTypePointer _spStructure; + + IDType _maskUID; + + + public: + + ~BoostMaskAccessor(); + + // import of structure sets (loading from data) is done elsewhere. Structures are only voxelized here. + // here the original RTToolbox voxelization shall be implemented + BoostMaskAccessor(StructTypePointer aStructurePointer, GeometricInfoPtr aGeometricInfoPtr); + + /*! @brief voxelization of the given structures according to the original RTToolbox algorithm*/ + void updateMask(); + + /*! @brief get vector conatining al relevant voxels that are inside the given structure*/ + MaskVoxelListPointer getRelevantVoxelVector(); + /*! @brief get vector conatining al relevant voxels that have a relevant volume above the given threshold and are inside the given structure*/ + MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold); + + /*!@brief determine how a given voxel on the dose grid is masked + * @param aID ID of the voxel in grid. + * @param voxel Reference to the voxel. + * @post after a valid call voxel containes the information of the specified grid voxel. If aID is not valid, voxel values are undefined. + * The relevant volume fraction will be set to zero. + * @return Indicates of the voxel exists and therefore if parameter voxel containes valid values.*/ + bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const; + + bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const; + + /*! @brief give access to GeometricInfo*/ + const core::GeometricInfo& getGeometricInfo() const; + + /* @ brief is true if dose is on a homogeneous grid */ + // Inhomogeneous grids are not supported at the moment, but if they will + // be supported in the future the interface does not need to change. + bool isGridHomogeneous() const + { + return true; + }; + + IDType getMaskUID() const + { + return _maskUID; + }; + + }; + } +} + +#endif diff --git a/testing/examples/DVHCalculatorExampleTest.cpp b/testing/examples/DVHCalculatorExampleTest.cpp index a65046b..7b64a53 100644 --- a/testing/examples/DVHCalculatorExampleTest.cpp +++ b/testing/examples/DVHCalculatorExampleTest.cpp @@ -1,356 +1,380 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmrt/drtdose.h" #include "dcmtk/dcmrt/drtstrct.h" #include "rttbBaseType.h" #include "rttbDVHCalculator.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbOTBMaskAccessor.h" #include "rttbMaskBoost.h" #include "../masks/rttbMaskVoxelListTester.h" +#include "rttbBoostMaskAccessor.h" namespace rttb { namespace testing { /*! @brief DVHCalculatorTest. Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed! */ int DVHCalculatorExampleTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; typedef core::DVHCalculator::MaskedDoseIteratorPointer MaskedDoseIteratorPointer; typedef masks::OTBMaskAccessor::StructTypePointer StructTypePointer; typedef core::DVH::DVHPointer DVHPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; typedef masks::OTBMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; typedef masks::OTBMaskAccessor::MaskVoxelList MaskVoxelList; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: structure file name // 2: dose1 file name // 3: dose2 file name // 4: dose3 file name std::string RTSTRUCT_FILENAME; std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; std::string RTDOSE3_FILENAME; if (argc > 1) { RTSTRUCT_FILENAME = argv[1]; } if (argc > 2) { RTDOSE_FILENAME = argv[2]; } if (argc > 3) { RTDOSE2_FILENAME = argv[3]; } if (argc > 4) { RTDOSE3_FILENAME = argv[4]; } OFCondition status; DcmFileFormat fileformat; // read dicom-rt dose ::DRTDoseIOD rtdose1; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //create a vector of MaskAccessors (one for each structure) StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTSTRUCT_FILENAME.c_str()).generateStructureSet(); //storeage for mask accessors to reduce time spent on voxelization (perform only once) std::vector rtStructSetMaskAccessorVec; ::DRTDoseIOD rtdose2; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2(RTDOSE2_FILENAME.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); ::DRTDoseIOD rtdose3; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator3(RTDOSE3_FILENAME.c_str()); DoseAccessorPointer doseAccessor3(doseAccessorGenerator3.generateDoseAccessor()); //start evaluation clock_t start(clock()); if (rtStructureSet->getNumberOfStructures() > 0) { for (int j = 0; j < rtStructureSet->getNumberOfStructures(); j++) { std::cout << rtStructureSet->getStructure(j)->getLabel() << std::endl; /**/ boost::shared_ptr geometricPtr = boost::make_shared(doseAccessor1->getGeometricInfo()); rttb::masks::MaskBoost maskBoost = rttb::masks::MaskBoost(geometricPtr, rtStructureSet->getStructure(j)); MaskVoxelListPointer voxelListBoost = maskBoost.getRelevantVoxelVector(); + + boost::shared_ptr spBoostMaskAccessorTmp = boost::make_shared(rtStructureSet->getStructure(j),geometricPtr); + spBoostMaskAccessorTmp->updateMask(); + MaskAccessorPointer spBoostMaskAccessor(spBoostMaskAccessorTmp); + + boost::shared_ptr spMaskedDoseIteratorBoostTmp = + boost::make_shared(spBoostMaskAccessor, doseAccessor1); + DoseIteratorPointer spMaskedDoseIteratorBoost(spMaskedDoseIteratorBoostTmp); + + rttb::core::DVHCalculator calcBoost(spMaskedDoseIteratorBoost, (rtStructureSet->getStructure(j))->getUID(), + doseAccessor1->getDoseUID()); + rttb::core::DVH dvhBoost = *(calcBoost.generateDVH()); + + //DEBUG OUTPUT + std::cout << "=== Dose 1 Structure "< spOTBMaskAccessor = boost::make_shared(rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); spOTBMaskAccessor->updateMask(); MaskAccessorPointer spMaskAccessor(spOTBMaskAccessor); MaskVoxelListPointer relVoxelOTB2 = spMaskAccessor->getRelevantVoxelVector(); MaskVoxelListTester listComp(voxelListBoost, relVoxelOTB2); CHECK_TESTER(listComp); //create corresponding MaskedDoseIterator boost::shared_ptr spMaskedDoseIteratorTmp = boost::make_shared(spMaskAccessor, doseAccessor1); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); //store MaskAccessor for each structure (later reuse) rtStructSetMaskAccessorVec.push_back(spMaskAccessor); //calculate DVH rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor1->getDoseUID()); rttb::core::DVH dvh = *(calc.generateDVH()); - /*//DEBUG OUTPUT + //DEBUG OUTPUT std::cout << "=== Dose 1 Structure "< spMaskedDoseIteratorTmp = boost::make_shared(rtStructSetMaskAccessorVec.at(j), doseAccessor2); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); //calculate DVH rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor2->getDoseUID()); rttb::core::DVH dvh = *(calc.generateDVH()); /*//DEBUG OUTPUT std::cout << "=== Dose 2 Structure "< spMaskedDoseIteratorTmp = boost::make_shared(rtStructSetMaskAccessorVec.at(j), doseAccessor3); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); //calculate DVH rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor3->getDoseUID()); rttb::core::DVH dvh = *(calc.generateDVH()); /*//DEBUG OUTPUT std::cout << "=== Dose 3 Structure "<