# HG changeset patch # User Sebastien Jodogne # Date 1605003088 -3600 # Node ID a4418a489e86a79762cb3d8acbeaaae975ab2423 # Parent 53d378ef72778d5eba6c9cd1342b3738c8206fa2 improving robustness of DicomInstanceParameters diff -r 53d378ef7277 -r a4418a489e86 OrthancStone/Sources/Loaders/OrthancMultiframeVolumeLoader.cpp --- a/OrthancStone/Sources/Loaders/OrthancMultiframeVolumeLoader.cpp Tue Nov 10 10:21:10 2020 +0100 +++ b/OrthancStone/Sources/Loaders/OrthancMultiframeVolumeLoader.cpp Tue Nov 10 11:11:28 2020 +0100 @@ -208,7 +208,7 @@ switch (parameters.GetSopClassUid()) { case OrthancStone::SopClassUid_RTDose: - spacingZ = parameters.GetThickness(); + spacingZ = parameters.GetSliceThickness(); break; default: diff -r 53d378ef7277 -r a4418a489e86 OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp --- a/OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp Tue Nov 10 10:21:10 2020 +0100 +++ b/OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp Tue Nov 10 11:11:28 2020 +0100 @@ -36,37 +36,28 @@ namespace OrthancStone { - void DicomInstanceParameters::Data::ComputeDoseOffsets(const Orthanc::DicomMap& dicom) + void DicomInstanceParameters::Data::ExtractFrameOffsets(const Orthanc::DicomMap& dicom) { // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html + std::string increment; + + if (dicom.LookupStringValue(increment, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER, false)) { - std::string increment; - - if (dicom.LookupStringValue(increment, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER, false)) + Orthanc::Toolbox::ToUpperCase(increment); + if (increment != "3004,000C") // This is the "Grid Frame Offset Vector" tag (DICOM_TAG_GRID_FRAME_OFFSET_VECTOR) { - Orthanc::Toolbox::ToUpperCase(increment); - if (increment != "3004,000C") // This is the "Grid Frame Offset Vector" tag (DICOM_TAG_GRID_FRAME_OFFSET_VECTOR) - { - LOG(ERROR) << "RT-DOSE: Bad value for the \"FrameIncrementPointer\" tag"; - return; - } + LOG(WARNING) << "Bad value for the FrameIncrementPointer tags in a multiframe image"; + return; } } if (!LinearAlgebra::ParseVector(frameOffsets_, dicom, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR) || - frameOffsets_.size() < imageInformation_.GetNumberOfFrames()) + frameOffsets_.size() != imageInformation_.GetNumberOfFrames()) { - LOG(ERROR) << "RT-DOSE: No information about the 3D location of some slice(s)"; + LOG(INFO) << "The frame offset information is missing in a multiframe image"; frameOffsets_.clear(); } - else - { - if (frameOffsets_.size() >= 2) - { - thickness_ = std::abs(frameOffsets_[1] - frameOffsets_[0]); - } - } } @@ -95,9 +86,9 @@ sopClassUid_ = StringToSopClassUid(s); } - if (!dicom.ParseDouble(thickness_, Orthanc::DICOM_TAG_SLICE_THICKNESS)) + if (!dicom.ParseDouble(sliceThickness_, Orthanc::DICOM_TAG_SLICE_THICKNESS)) { - thickness_ = 100.0 * std::numeric_limits::epsilon(); + sliceThickness_ = 100.0 * std::numeric_limits::epsilon(); } GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dicom); @@ -109,16 +100,16 @@ geometry_ = CoordinateSystem3D(position, orientation); } + ExtractFrameOffsets(dicom); + if (sopClassUid_ == SopClassUid_RTDose) { - ComputeDoseOffsets(dicom); - static const Orthanc::DicomTag DICOM_TAG_DOSE_UNITS(0x3004, 0x0002); if (!dicom.LookupStringValue(doseUnits_, DICOM_TAG_DOSE_UNITS, false)) { LOG(ERROR) << "Tag DoseUnits (0x3004, 0x0002) is missing in " << sopInstanceUid_; - doseUnits_ = ""; + doseUnits_.clear(); } } @@ -178,6 +169,8 @@ defaultWindowingWidth_ = 0; } + expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; // Rough guess + if (sopClassUid_ == SopClassUid_RTDose) { switch (imageInformation_.GetBitsStored()) @@ -191,7 +184,7 @@ break; default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + break; } } else if (isColor_) @@ -202,10 +195,6 @@ { expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16; } - else - { - expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; - } // This computes the "IndexInSeries" metadata from Orthanc (check // out "Orthanc::ServerIndex::Store()") @@ -225,22 +214,19 @@ { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - else if (sopClassUid_ == SopClassUid_RTDose) + else if (frameOffsets_.empty()) { - if (frame >= frameOffsets_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } + return geometry_; + } + else + { + assert(frameOffsets_.size() == imageInformation_.GetNumberOfFrames()); return CoordinateSystem3D( geometry_.GetOrigin() + frameOffsets_[frame] * geometry_.GetNormal(), geometry_.GetAxisX(), geometry_.GetAxisY()); } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } } @@ -262,7 +248,7 @@ double distance; return (CoordinateSystem3D::ComputeDistance(distance, tmp, plane) && - distance <= thickness_ / 2.0); + distance <= sliceThickness_ / 2.0); } void DicomInstanceParameters::Data::ApplyRescaleAndDoseScaling(Orthanc::ImageAccessor& image, @@ -282,7 +268,8 @@ offset = rescaleIntercept_; } - if ( (factor != 1.0) || (offset != 0.0) ) + if (!LinearAlgebra::IsNear(factor, 1) || + !LinearAlgebra::IsNear(offset, 0)) { const unsigned int width = image.GetWidth(); const unsigned int height = image.GetHeight(); @@ -371,9 +358,9 @@ Orthanc::ImageAccessor* DicomInstanceParameters::ConvertToFloat(const Orthanc::ImageAccessor& pixelData) const { std::unique_ptr converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, - pixelData.GetWidth(), - pixelData.GetHeight(), - false)); + pixelData.GetWidth(), + pixelData.GetHeight(), + false)); Orthanc::ImageProcessing::Convert(*converted, pixelData); @@ -438,16 +425,18 @@ data_.defaultWindowingWidth_); } - - if (data_.imageInformation_.GetPhotometricInterpretation() - == Orthanc::PhotometricInterpretation_Monochrome1) + switch (data_.imageInformation_.GetPhotometricInterpretation()) { - texture->SetInverted(true); - } - else if (data_.imageInformation_.GetPhotometricInterpretation() - == Orthanc::PhotometricInterpretation_Monochrome2) - { - texture->SetInverted(false); + case Orthanc::PhotometricInterpretation_Monochrome1: + texture->SetInverted(true); + break; + + case Orthanc::PhotometricInterpretation_Monochrome2: + texture->SetInverted(false); + break; + + default: + break; } return texture.release(); diff -r 53d378ef7277 -r a4418a489e86 OrthancStone/Sources/Toolbox/DicomInstanceParameters.h --- a/OrthancStone/Sources/Toolbox/DicomInstanceParameters.h Tue Nov 10 10:21:10 2020 +0100 +++ b/OrthancStone/Sources/Toolbox/DicomInstanceParameters.h Tue Nov 10 11:11:28 2020 +0100 @@ -45,7 +45,7 @@ std::string sopInstanceUid_; Orthanc::DicomImageInformation imageInformation_; SopClassUid sopClassUid_; - double thickness_; + double sliceThickness_; double pixelSpacingX_; double pixelSpacingY_; CoordinateSystem3D geometry_; @@ -63,7 +63,7 @@ std::string doseUnits_; double doseGridScaling_; - void ComputeDoseOffsets(const Orthanc::DicomMap& dicom); + void ExtractFrameOffsets(const Orthanc::DicomMap& dicom); explicit Data(const Orthanc::DicomMap& dicom); @@ -135,9 +135,9 @@ return data_.sopClassUid_; } - double GetThickness() const + double GetSliceThickness() const { - return data_.thickness_; + return data_.sliceThickness_; } double GetPixelSpacingX() const