changeset 1634:a4418a489e86

improving robustness of DicomInstanceParameters
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 10 Nov 2020 11:11:28 +0100
parents 53d378ef7277
children 1a714e21ea7c
files OrthancStone/Sources/Loaders/OrthancMultiframeVolumeLoader.cpp OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp OrthancStone/Sources/Toolbox/DicomInstanceParameters.h
diffstat 3 files changed, 46 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- 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:
--- 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<double>::epsilon();
+      sliceThickness_ = 100.0 * std::numeric_limits<double>::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<Orthanc::Image> 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();
--- 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