diff --git a/code/io/dicom/rttbDicomDoseAccessor.cpp b/code/io/dicom/rttbDicomDoseAccessor.cpp index aafe368..5c8c702 100644 --- a/code/io/dicom/rttbDicomDoseAccessor.cpp +++ b/code/io/dicom/rttbDicomDoseAccessor.cpp @@ -1,303 +1,303 @@ // ----------------------------------------------------------------------- // 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 "rttbDicomDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" namespace rttb { namespace io { namespace dicom { DicomDoseAccessor::~DicomDoseAccessor() { } DicomDoseAccessor::DicomDoseAccessor(DRTDoseIODPtr aDRTDoseIODP) { _dose = aDRTDoseIODP; OFString uid; _dose->getSeriesInstanceUID(uid); _doseUID = uid.c_str(); this->begin(); } bool DicomDoseAccessor::begin() { assembleGeometricInfo(); doseData.clear(); OFString doseGridScalingStr; this->_dose->getDoseGridScaling(doseGridScalingStr); try { _doseGridScaling = boost::lexical_cast(doseGridScalingStr.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Dose grid scaling not readable or = 0!") ; } OFCondition status; DcmFileFormat fileformat; DcmItem doseitem; status = _dose->write(doseitem); if (status.good()) { unsigned long count; const Uint16* pixelData; status = doseitem.findAndGetUint16Array(DcmTagKey(0x7fe0, 0x0010), pixelData, &count); if (status.good()) { for (unsigned int i = 0; i < static_cast(this->_geoInfo.getNumberOfVoxels()); i++) { this->doseData.push_back(pixelData[i]); } return true; } else { throw io::dicom::DcmrtException("Read Pixel Data (7FE0,0010) failed!"); } } else { throw io::dicom::DcmrtException("Read DICOM-RT Dose file failed!"); } } bool DicomDoseAccessor::assembleGeometricInfo() { Uint16 temp = 0; this->_dose->getColumns(temp); _geoInfo.setNumColumns(temp); temp = 0; this->_dose->getRows(temp); _geoInfo.setNumRows(temp); if (_geoInfo.getNumColumns() == 0 || _geoInfo.getNumRows() == 0) { throw core::InvalidDoseException("Empty dicom dose!") ; } OFString numberOfFramesStr; OFString imageOrientationRowX, imageOrientationRowY, imageOrientationRowZ; OFString imageOrientationColumnX, imageOrientationColumnY, imageOrientationColumnZ; WorldCoordinate3D imageOrientationRow; WorldCoordinate3D imageOrientationColumn; try { this->_dose->getNumberOfFrames(numberOfFramesStr); _geoInfo.setNumSlices(boost::lexical_cast(numberOfFramesStr.c_str())); _dose->getImageOrientationPatient(imageOrientationRowX, 0); _dose->getImageOrientationPatient(imageOrientationRowY, 1); _dose->getImageOrientationPatient(imageOrientationRowZ, 2); _dose->getImageOrientationPatient(imageOrientationColumnX, 3); _dose->getImageOrientationPatient(imageOrientationColumnY, 4); _dose->getImageOrientationPatient(imageOrientationColumnZ, 5); imageOrientationRow(0) = boost::lexical_cast(imageOrientationRowX.c_str()); imageOrientationRow(1) = boost::lexical_cast(imageOrientationRowY.c_str()); imageOrientationRow(2) = boost::lexical_cast(imageOrientationRowZ.c_str()); imageOrientationColumn(0) = boost::lexical_cast(imageOrientationColumnX.c_str()); imageOrientationColumn(1) = boost::lexical_cast(imageOrientationColumnY.c_str()); imageOrientationColumn(2) = boost::lexical_cast(imageOrientationColumnZ.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("boost::lexical_cast failed! Empty dicom dose!") ; } /*Get orientation*/ OrientationMatrix orientation; orientation(0, 0) = imageOrientationRow.x(); orientation(1, 0) = imageOrientationRow.y(); orientation(2, 0) = imageOrientationRow.z(); orientation(0, 1) = imageOrientationColumn.x(); orientation(1, 1) = imageOrientationColumn.y(); orientation(2, 1) = imageOrientationColumn.z(); WorldCoordinate3D perpendicular = imageOrientationRow.cross(imageOrientationColumn); orientation(0, 2) = perpendicular.x(); orientation(1, 2) = perpendicular.y(); orientation(2, 2) = perpendicular.z(); _geoInfo.setOrientationMatrix(orientation); OFString imagePositionX, imagePositionY, imagePositionZ; _dose->getImagePositionPatient(imagePositionX, 0); _dose->getImagePositionPatient(imagePositionY, 1); _dose->getImagePositionPatient(imagePositionZ, 2); WorldCoordinate3D imagePositionPatient; try { imagePositionPatient(0) = boost::lexical_cast(imagePositionX.c_str()); imagePositionPatient(1) = boost::lexical_cast(imagePositionY.c_str()); imagePositionPatient(2) = boost::lexical_cast(imagePositionZ.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Can not read image position X/Y/Z!") ; } _geoInfo.setImagePositionPatient(imagePositionPatient); /*Get spacing*/ SpacingVectorType3D spacingVector; OFString pixelSpacingRowStr, pixelSpacingColumnStr, sliceThicknessStr; _dose->getPixelSpacing(pixelSpacingRowStr, 0); _dose->getPixelSpacing(pixelSpacingColumnStr, 1); try { - spacingVector(0) = boost::lexical_cast(pixelSpacingRowStr.c_str()); - spacingVector(1) = boost::lexical_cast(pixelSpacingColumnStr.c_str()); + spacingVector(1) = boost::lexical_cast(pixelSpacingRowStr.c_str()); + spacingVector(0) = boost::lexical_cast(pixelSpacingColumnStr.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Can not read Pixel Spacing Row/Column!") ; } _geoInfo.setSpacing(spacingVector); if (_geoInfo.getPixelSpacingRow() == 0 || _geoInfo.getPixelSpacingColumn() == 0) { throw core::InvalidDoseException("Pixel spacing = 0!"); } _dose->getSliceThickness(sliceThicknessStr); try { spacingVector(2) = boost::lexical_cast(sliceThicknessStr.c_str()); } catch (boost::bad_lexical_cast&) { spacingVector(2) = 0 ; } if (spacingVector(2) == 0) { OFVector gridFrameOffsetVector; _dose->getGridFrameOffsetVector(gridFrameOffsetVector); if (gridFrameOffsetVector.size() >= 2) { spacingVector(2) = gridFrameOffsetVector.at(1) - gridFrameOffsetVector.at( 0); //read slice thickness from GridFrameOffsetVector (3004,000c) } if (spacingVector(2) == 0) { OFCondition status; DcmItem doseitem; OFString pixelSpacingBetweenSlices; status = _dose->write(doseitem); if (status.good()) { status = doseitem.findAndGetOFString(DcmTagKey(0x0018, 0x0088), pixelSpacingBetweenSlices); try { spacingVector(2) = boost::lexical_cast (pixelSpacingBetweenSlices.c_str());//read slice thickness from PixelSpacingBetweenSlices (0018,0088) } catch (boost::bad_lexical_cast&) { spacingVector(2) = 0 ; } } //if no useful tags to compute slicing -> set slice thickness to spacingVector(0) if (spacingVector(2) == 0) { std::cerr << "sliceThickness == 0! It wird be replaced with pixelSpacingRow=" << _geoInfo.getPixelSpacingRow() << "!" << std::endl; spacingVector(2) = spacingVector(0); } } } _geoInfo.setSpacing(spacingVector); return true; } DoseTypeGy DicomDoseAccessor::getDoseAt(const VoxelGridID aID) const { return doseData.at(aID) * _doseGridScaling; } DoseTypeGy DicomDoseAccessor::getDoseAt(const VoxelGridIndex3D& aIndex) const { VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getDoseAt(aVoxelGridID); } else { return -1; } } } } } diff --git a/code/io/helax/rttbDicomHelaxDoseAccessor.cpp b/code/io/helax/rttbDicomHelaxDoseAccessor.cpp index 8389c0c..fa67eda 100644 --- a/code/io/helax/rttbDicomHelaxDoseAccessor.cpp +++ b/code/io/helax/rttbDicomHelaxDoseAccessor.cpp @@ -1,317 +1,317 @@ // ----------------------------------------------------------------------- // 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 "boost/filesystem/operations.hpp" #include "boost/filesystem/path.hpp" #include "boost/progress.hpp" #include #include "rttbDicomHelaxDoseAccessor.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace io { namespace helax { DicomHelaxDoseAccessor::~DicomHelaxDoseAccessor() { } DicomHelaxDoseAccessor::DicomHelaxDoseAccessor(std::vector aDICOMRTDoseVector) { for (int i = 0; i < aDICOMRTDoseVector.size(); i++) { _doseVector.push_back(aDICOMRTDoseVector.at(i)); } this->begin(); } bool DicomHelaxDoseAccessor::begin() { if (_doseVector.size() == 0) { throw core::InvalidParameterException(" The size of aDICOMRTDoseVector is 0!"); } assembleGeometricInfo(); _doseData.clear(); OFString doseGridScalingStr; char* pEnd; _doseVector.at(0)->getDoseGridScaling( doseGridScalingStr);//get the first dose grid scaling as _doseGridScaling _doseGridScaling = strtod(doseGridScalingStr.c_str(), &pEnd); if (*pEnd != '\0' || _doseGridScaling == 0) { throw core::InvalidDoseException("Dose grid scaling not readable or = 0!") ; } for (int i = 0; i < _doseVector.size(); i++) { DRTDoseIODPtr dose = _doseVector.at(i); OFString currentDoseGridScalingStr; dose->getDoseGridScaling(currentDoseGridScalingStr); double currentDoseGridScaling = strtod(currentDoseGridScalingStr.c_str(), &pEnd); if (*pEnd != '\0' || currentDoseGridScaling == 0) { throw core::InvalidDoseException("Dose grid scaling not readable or = 0!") ; } OFCondition status; DcmFileFormat fileformat; DcmItem doseitem; status = dose->write(doseitem); if (status.good()) { unsigned long count; const Uint16* pixelData; status = doseitem.findAndGetUint16Array(DcmTagKey(0x7fe0, 0x0010), pixelData, &count); if (status.good()) { for (unsigned int i = 0; i < static_cast(_geoInfo.getNumColumns()*_geoInfo.getNumRows()); i++) { this->_doseData.push_back(pixelData[i]*currentDoseGridScaling / _doseGridScaling); //recalculate dose data } } else { throw dicom::DcmrtException("Read Pixel Data (7FE0,0010) failed!"); } } else { throw dicom::DcmrtException("Read DICOM-RT Dose file failed!"); } } //std::cout << _doseData.size()<getColumns(temp); _geoInfo.setNumColumns(temp); temp = 0; dose->getRows(temp); _geoInfo.setNumRows(temp); OFString numberOfFramesStr; dose->getNumberOfFrames(numberOfFramesStr); if (!numberOfFramesStr.empty()) { _geoInfo.setNumSlices(boost::lexical_cast(numberOfFramesStr.c_str())); } else { _geoInfo.setNumSlices((VoxelGridDimensionType)_doseVector.size()); } if (_geoInfo.getNumColumns() == 0 || _geoInfo.getNumRows() == 0 || _geoInfo.getNumSlices() == 0) { throw core::InvalidDoseException("Empty dicom dose!") ; } OFString imageOrientationRowX; dose->getImageOrientationPatient(imageOrientationRowX, 0); OFString imageOrientationRowY; dose->getImageOrientationPatient(imageOrientationRowY, 1); OFString imageOrientationRowZ; dose->getImageOrientationPatient(imageOrientationRowZ, 2); OFString imageOrientationColumnX; dose->getImageOrientationPatient(imageOrientationColumnX, 3); OFString imageOrientationColumnY; dose->getImageOrientationPatient(imageOrientationColumnY, 4); OFString imageOrientationColumnZ; dose->getImageOrientationPatient(imageOrientationColumnZ, 5); WorldCoordinate3D imageOrientationRow; imageOrientationRow(0) = boost::lexical_cast(imageOrientationRowX.c_str()); imageOrientationRow(1) = boost::lexical_cast(imageOrientationRowY.c_str()); imageOrientationRow(2) = boost::lexical_cast(imageOrientationRowZ.c_str()); WorldCoordinate3D imageOrientationColumn; imageOrientationColumn(0) = boost::lexical_cast(imageOrientationColumnX.c_str()); imageOrientationColumn(1) = boost::lexical_cast(imageOrientationColumnY.c_str()); imageOrientationColumn(2) = boost::lexical_cast(imageOrientationColumnZ.c_str()); OrientationMatrix orientation; orientation(0, 0) = imageOrientationRow.x(); orientation(1, 0) = imageOrientationRow.y(); orientation(2, 0) = imageOrientationRow.z(); orientation(0, 1) = imageOrientationColumn.x(); orientation(1, 1) = imageOrientationColumn.y(); orientation(2, 1) = imageOrientationColumn.z(); WorldCoordinate3D perpendicular = imageOrientationRow.cross(imageOrientationColumn); orientation(0, 2) = perpendicular.x(); orientation(1, 2) = perpendicular.y(); orientation(2, 2) = perpendicular.z(); _geoInfo.setOrientationMatrix(orientation); OFString imagePositionX; dose->getImagePositionPatient(imagePositionX, 0); OFString imagePositionY; dose->getImagePositionPatient(imagePositionY, 1); OFString imagePositionZ; dose->getImagePositionPatient(imagePositionZ, 2); WorldCoordinate3D imagePositionPatient; char* pEnd; imagePositionPatient(0) = strtod(imagePositionX.c_str(), &pEnd); if (*pEnd != '\0') { throw core::InvalidDoseException("Can not read image position X!"); } imagePositionPatient(1) = strtod(imagePositionY.c_str(), &pEnd); if (*pEnd != '\0') { throw core::InvalidDoseException("Can not read image position Y!"); } imagePositionPatient(2) = strtod(imagePositionZ.c_str(), &pEnd); if (*pEnd != '\0') { throw core::InvalidDoseException("Can not read image position Z!"); } _geoInfo.setImagePositionPatient(imagePositionPatient); SpacingVectorType3D spacingVector; OFString pixelSpacingRowStr; dose->getPixelSpacing(pixelSpacingRowStr, 0); - spacingVector(0) = strtod(pixelSpacingRowStr.c_str(), &pEnd); + spacingVector(1) = strtod(pixelSpacingRowStr.c_str(), &pEnd); if (*pEnd != '\0') { throw core::InvalidDoseException("Can not read Pixel Spacing Row!"); } OFString pixelSpacingColumnStr; dose->getPixelSpacing(pixelSpacingColumnStr, 1); - spacingVector(1) = strtod(pixelSpacingColumnStr.c_str(), &pEnd); + spacingVector(0) = strtod(pixelSpacingColumnStr.c_str(), &pEnd); if (*pEnd != '\0') { throw core::InvalidDoseException("Can not read Pixel Spacing Column!"); } _geoInfo.setSpacing(spacingVector); if (_geoInfo.getPixelSpacingRow() == 0 || _geoInfo.getPixelSpacingColumn() == 0) { throw core::InvalidDoseException("Pixel spacing not readable or = 0!"); } OFString sliceThicknessStr; dose->getSliceThickness(sliceThicknessStr); spacingVector(2) = strtod(sliceThicknessStr.c_str(), &pEnd); if (*pEnd != '\0') { throw core::InvalidDoseException("Can not read slice thickness!"); } if (spacingVector(2) == 0) { if (_doseVector.size() > 1) { DRTDoseIODPtr dose2 = _doseVector.at(1); OFString imagePositionZ2; dose2->getImagePositionPatient(imagePositionZ2, 2); spacingVector(2) = strtod(imagePositionZ2.c_str(), &pEnd) - imagePositionPatient(2); if (*pEnd != '\0') { throw core::InvalidDoseException("Can not read image position Z!"); } } else { std::cerr << "sliceThickness == 0! It will be replaced with pixelSpacingRow=" << _geoInfo.getPixelSpacingRow() << "!" << std::endl; spacingVector(2) = spacingVector(0); } } _geoInfo.setSpacing(spacingVector); return true; } DoseTypeGy DicomHelaxDoseAccessor::getDoseAt(const VoxelGridID aID) const { return _doseData.at(aID) * _doseGridScaling; } DoseTypeGy DicomHelaxDoseAccessor::getDoseAt(const VoxelGridIndex3D& aIndex) const { VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getDoseAt(aVoxelGridID); } else { return -1; } } } } } diff --git a/testing/io/dicom/CMakeLists.txt b/testing/io/dicom/CMakeLists.txt index e032960..2af345b 100644 --- a/testing/io/dicom/CMakeLists.txt +++ b/testing/io/dicom/CMakeLists.txt @@ -1,28 +1,29 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(DICOMIO_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbDicomIOTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- ADD_TEST(DicomDoseAccessorGeneratorTest ${DICOMIO_TEST} DicomDoseAccessorGeneratorTest "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantFifty.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncrease3D.dcm" ) ADD_TEST(DicomIOTest ${DICOMIO_TEST} DicomIOTest "${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo.dcm" -"${TEST_DATA_ROOT}/DICOM/TestDose/ConstantFifty.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncrease3D.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/dicompylerTestDose.dcm" ) +"${TEST_DATA_ROOT}/DICOM/TestDose/ConstantFifty.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncrease3D.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/dicompylerTestDose.dcm" +"${TEST_DATA_ROOT}/DICOM/TestDose/InhomogeneousGrid.dcm" ) ADD_TEST(DicomStructureSetGeneratorTest ${DICOMIO_TEST} DicomStructureSetGeneratorTest "${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" ) RTTB_CREATE_TEST_MODULE(rttbDicomIO DEPENDS RTTBDicomIO PACKAGE_DEPENDS Boost Litmus DCMTK) diff --git a/testing/io/dicom/DicomIOTest.cpp b/testing/io/dicom/DicomIOTest.cpp index ebd47cd..e89cfc2 100644 --- a/testing/io/dicom/DicomIOTest.cpp +++ b/testing/io/dicom/DicomIOTest.cpp @@ -1,227 +1,240 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbDoseIteratorInterface.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomIODDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" namespace rttb { namespace testing { /*!@brief DicomIOTest - test the IO for dicom data 1) test dicom dose import if geometric info was set correctly 2) test dicom dose import accessing dose data and converting 3) check if dicom tags are correctly read 4) test structure import WARNING: The values for comparison need to be adjusted if the input files are changed! */ int DicomIOTest(int argc, char* argv[]) { typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: structure file name // 2: dose1 file name // 3: dose2 file name // 4: dose3 file name + // 5: dose4 file name + // 6: dose5 file name std::string RTSTRUCT_FILENAME; std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; std::string RTDOSE3_FILENAME; std::string RTDOSE4_FILENAME; + std::string RTDOSE5_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]; } if (argc > 5) { RTDOSE4_FILENAME = argv[5]; } + if(argc > 6) + { + RTDOSE5_FILENAME = argv[6]; + } OFCondition status; DcmFileFormat fileformat; /* read dicom-rt dose */ io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //1) test dicom dose import if geometric info was set correctly core::GeometricInfo geoInfo = doseAccessor1->getGeometricInfo(); CHECK_EQUAL(45, geoInfo.getNumRows()); CHECK_EQUAL(67, geoInfo.getNumColumns()); CHECK_EQUAL(64, geoInfo.getNumSlices()); CHECK_EQUAL(OrientationMatrix(), geoInfo.getOrientationMatrix()); SpacingVectorType3D pixelSpacing(5, 5, 5); CHECK_EQUAL(pixelSpacing, geoInfo.getSpacing()); WorldCoordinate3D imagePositionPatient(-170.556642, -273.431642, -674); CHECK_EQUAL(imagePositionPatient, geoInfo.getImagePositionPatient()); + //test geometric info of an inhomogeneous dose grid + io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator5(RTDOSE5_FILENAME.c_str()); + DoseAccessorPointer doseAccessor5(doseAccessorGenerator5.generateDoseAccessor()); + + SpacingVectorType3D pixelSpacing5(2,3,2); + CHECK_EQUAL(pixelSpacing5, doseAccessor5->getGeometricInfo().getSpacing()); + const VoxelGridID start = 0; const VoxelGridIndex3D start3D(0); VoxelGridID end, inbetween; VoxelGridIndex3D end3D, inbetween3D; //2) test dicom dose import accessing dose data and converting - CHECK_EQUAL(2, doseAccessor1->getDoseAt(start)); CHECK_EQUAL(2, doseAccessor1-> getDoseAt(start3D)); CHECK_EQUAL(doseAccessor1->getDoseAt(start), doseAccessor1-> getDoseAt(start3D)); inbetween = int(std::floor(doseAccessor1->getGridSize() / 2.0)); doseAccessor1->getGeometricInfo().convert(inbetween, inbetween3D); CHECK_EQUAL(2, doseAccessor1->getDoseAt(inbetween)); CHECK_EQUAL(2, doseAccessor1-> getDoseAt(inbetween3D)); CHECK_EQUAL(doseAccessor1->getDoseAt(inbetween), doseAccessor1-> getDoseAt(inbetween3D)); end = doseAccessor1->getGridSize() - 1; doseAccessor1->getGeometricInfo().convert(end, end3D); CHECK_EQUAL(2, doseAccessor1->getDoseAt(end)); CHECK_EQUAL(2, doseAccessor1-> getDoseAt(end3D)); CHECK_EQUAL(doseAccessor1->getDoseAt(end), doseAccessor1-> getDoseAt(end3D)); ::DRTDoseIOD rtdose2; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2(RTDOSE2_FILENAME.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); //2) test dicom dose import accessing dose data and converting CHECK_EQUAL(50, doseAccessor2->getDoseAt(start)); CHECK_EQUAL(50, doseAccessor2-> getDoseAt(start3D)); CHECK_EQUAL(doseAccessor2->getDoseAt(start), doseAccessor2-> getDoseAt(start3D)); inbetween = int(std::floor(doseAccessor2->getGridSize() / 2.0)); doseAccessor2->getGeometricInfo().convert(inbetween, inbetween3D); CHECK_EQUAL(50, doseAccessor2->getDoseAt(inbetween)); CHECK_EQUAL(50, doseAccessor2-> getDoseAt(inbetween3D)); CHECK_EQUAL(doseAccessor2->getDoseAt(inbetween), doseAccessor2-> getDoseAt(inbetween3D)); end = doseAccessor2->getGridSize() - 1; doseAccessor2->getGeometricInfo().convert(end, end3D); CHECK_EQUAL(50, doseAccessor2->getDoseAt(end)); CHECK_EQUAL(50, doseAccessor2-> getDoseAt(end3D)); CHECK_EQUAL(doseAccessor2->getDoseAt(end), doseAccessor2-> getDoseAt(end3D)); ::DRTDoseIOD rtdose3; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator3(RTDOSE3_FILENAME.c_str()); DoseAccessorPointer doseAccessor3(doseAccessorGenerator3.generateDoseAccessor()); //2) test dicom dose import accessing dose data and converting CHECK_EQUAL(0, doseAccessor3->getDoseAt(start)); CHECK_EQUAL(0, doseAccessor3-> getDoseAt(start3D)); CHECK_EQUAL(doseAccessor3->getDoseAt(start), doseAccessor3-> getDoseAt(start3D)); inbetween = int(std::floor(doseAccessor3->getGridSize() / 2.0)); doseAccessor3->getGeometricInfo().convert(inbetween, inbetween3D); CHECK_EQUAL(0, doseAccessor3->getDoseAt(inbetween)); CHECK_EQUAL(0, doseAccessor3-> getDoseAt(inbetween3D)); CHECK_EQUAL(doseAccessor3->getDoseAt(inbetween), doseAccessor3-> getDoseAt(inbetween3D)); end = doseAccessor3->getGridSize() - 1; doseAccessor3->getGeometricInfo().convert(end, end3D); CHECK_CLOSE(1.46425, doseAccessor3->getDoseAt(end), errorConstant); CHECK_CLOSE(1.46425, doseAccessor3-> getDoseAt(end3D), errorConstant); CHECK_EQUAL(doseAccessor3->getDoseAt(end), doseAccessor3-> getDoseAt(end3D)); /* structure set */ StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTSTRUCT_FILENAME.c_str()).generateStructureSet(); //4) test structure import CHECK_EQUAL(10, rtStructureSet->getNumberOfStructures()); CHECK_EQUAL("Aussenkontur", (rtStructureSet->getStructure(0))->getLabel()); CHECK_EQUAL("Rueckenmark", (rtStructureSet->getStructure(1))->getLabel()); CHECK_EQUAL("Niere re.", (rtStructureSet->getStructure(2))->getLabel()); CHECK_EQUAL("Niere li.", (rtStructureSet->getStructure(3))->getLabel()); CHECK_EQUAL("Magen/DD", (rtStructureSet->getStructure(4))->getLabel()); CHECK_EQUAL("Leber", (rtStructureSet->getStructure(5))->getLabel()); CHECK_EQUAL("Darm", (rtStructureSet->getStructure(6))->getLabel()); CHECK_EQUAL("Ref.Pkt.", (rtStructureSet->getStructure(7))->getLabel()); CHECK_EQUAL("PTV", (rtStructureSet->getStructure(8))->getLabel()); CHECK_EQUAL("Boost", (rtStructureSet->getStructure(9))->getLabel()); //4) Test other tags (GridFrameOffsetVector(3004,000c) and PixelSpacingBetweenSlices(0018, 0088)) to compute dose slicing io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator4(RTDOSE4_FILENAME.c_str()); DoseAccessorPointer doseAccessor4(doseAccessorGenerator4.generateDoseAccessor()); rttb::SpacingVectorType3D spacingVec = doseAccessor4->getGeometricInfo().getSpacing(); CHECK_EQUAL(2.5, spacingVec.x()); CHECK_EQUAL(2.5, spacingVec.y()); CHECK_EQUAL(3, spacingVec.z()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb