diff Framework/Toolbox/Slice.cpp @ 117:42c05a3baee3 wasm

loading multi-frame instances as 3D volumes
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 28 Sep 2017 16:55:51 +0200
parents 2eca030792aa
children a4d0b6c82b29
line wrap: on
line diff
--- a/Framework/Toolbox/Slice.cpp	Mon Sep 25 13:43:47 2017 +0200
+++ b/Framework/Toolbox/Slice.cpp	Thu Sep 28 16:55:51 2017 +0200
@@ -21,32 +21,135 @@
 
 #include "Slice.h"
 
+#include "../Enumerations.h"
+
+#include <Core/Logging.h>
 #include <Core/OrthancException.h>
+#include <Core/Toolbox.h>
+
+#include <boost/lexical_cast.hpp>
 
 namespace OrthancStone
 {
+  static bool ParseDouble(double& target,
+                          const std::string& source)
+  {
+    try
+    {
+      target = boost::lexical_cast<double>(source);
+      return true;
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+      return false;
+    }
+  }
+  
+  bool Slice::ComputeRTDoseGeometry(const OrthancPlugins::DicomDatasetReader& reader,
+                                    unsigned int frame)
+  {
+    // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html
+    static const OrthancPlugins::DicomTag DICOM_TAG_GRID_FRAME_OFFSET_VECTOR(0x3004, 0x000c);
+    static const OrthancPlugins::DicomTag DICOM_TAG_FRAME_INCREMENT_POINTER(0x0028, 0x0009);
+
+    std::string increment = reader.GetStringValue(DICOM_TAG_FRAME_INCREMENT_POINTER, "");
+    std::string offsetTag;
+
+    bool ok = reader.GetDataset().GetStringValue(offsetTag, DICOM_TAG_GRID_FRAME_OFFSET_VECTOR);
+    if (!ok)
+    {
+      LOG(ERROR) << "Cannot read the \"GridFrameOffsetVector\" tag, check you are using Orthanc >= 1.3.1";
+      return false;
+    }
+
+    Orthanc::Toolbox::ToUpperCase(increment);
+    if (increment != "3004,000C" ||
+        offsetTag.empty())
+    {
+      return false;
+    }
+
+    std::vector<std::string> offsets;
+    Orthanc::Toolbox::TokenizeString(offsets, offsetTag, '\\');
+
+    if (frameCount_ == 0 ||
+        offsets.size() != frameCount_ ||
+        frame >= frameCount_)
+    {
+      LOG(ERROR) << "No information about the 3D location of some slice(s) in a RT DOSE";
+      return false;
+    }
+
+    double offset0, z;
+
+    if (!ParseDouble(offset0, offsets[0]) ||
+        !ParseDouble(z, offsets[frame]))
+    {
+      LOG(ERROR) << "Invalid syntax";
+      return false;
+    }
+
+    if (!GeometryToolbox::IsCloseToZero(offset0))
+    {
+      LOG(ERROR) << "Invalid syntax";
+      return false;
+    }
+
+    geometry_ = CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(),
+                                   geometry_.GetAxisX(),
+                                   geometry_.GetAxisY());
+    
+    return true;
+  }
+
+  
   bool Slice::ParseOrthancFrame(const OrthancPlugins::IDicomDataset& dataset,
                                 const std::string& instanceId,
                                 unsigned int frame)
   {
+    orthancInstanceId_ = instanceId;
+    frame_ = frame;
+    type_ = Type_OrthancDecodableFrame;
+
     OrthancPlugins::DicomDatasetReader reader(dataset);
 
-    unsigned int frameCount;
-    if (!reader.GetUnsignedIntegerValue(frameCount, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES))
+    sopClassUid_ = reader.GetStringValue(OrthancPlugins::DICOM_TAG_SOP_CLASS_UID, "");
+    if (sopClassUid_.empty())
     {
-      frameCount = 1;   // Assume instance with one frame
+      LOG(ERROR) << "Instance without a SOP class UID";
+      return false; 
+    }
+  
+    if (!reader.GetUnsignedIntegerValue(frameCount_, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES))
+    {
+      frameCount_ = 1;   // Assume instance with one frame
     }
 
-    if (frame >= frameCount)
+    if (frame >= frameCount_)
     {
       return false;
     }
 
-    if (!reader.GetDoubleValue(thickness_, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS))
+    if (!reader.GetUnsignedIntegerValue(width_, OrthancPlugins::DICOM_TAG_COLUMNS) ||
+        !reader.GetUnsignedIntegerValue(height_, OrthancPlugins::DICOM_TAG_ROWS))
     {
-      thickness_ = 100.0 * std::numeric_limits<double>::epsilon();
+      return false;
     }
 
+    thickness_ = 100.0 * std::numeric_limits<double>::epsilon();
+
+    std::string tmp;
+    if (dataset.GetStringValue(tmp, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS))
+    {
+      if (!tmp.empty() &&
+          !ParseDouble(thickness_, tmp))
+      {
+        return false;  // Syntax error
+      }
+    }
+    
+    converter_.ReadParameters(dataset);
+
     GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset);
 
     std::string position, orientation;
@@ -54,33 +157,47 @@
         dataset.GetStringValue(orientation, OrthancPlugins::DICOM_TAG_IMAGE_ORIENTATION_PATIENT))
     {
       geometry_ = CoordinateSystem3D(position, orientation);
+
+      bool ok = true;
+      SopClassUid tmp;
+
+      if (StringToSopClassUid(tmp, sopClassUid_))
+      {
+        switch (tmp)
+        {
+          case SopClassUid_RTDose:
+            type_ = Type_OrthancRawFrame;
+            ok = ComputeRTDoseGeometry(reader, frame);
+            break;
+            
+          default:
+            break;
+        }
+      }
+
+      if (!ok)
+      {
+        LOG(ERROR) << "Cannot deduce the 3D location of frame " << frame
+                   << " in instance " << instanceId << ", whose SOP class UID is: " << sopClassUid_;
+        return false;
+      }
     }
-      
-    if (reader.GetUnsignedIntegerValue(width_, OrthancPlugins::DICOM_TAG_COLUMNS) &&
-        reader.GetUnsignedIntegerValue(height_, OrthancPlugins::DICOM_TAG_ROWS))
-    {
-      orthancInstanceId_ = instanceId;
-      frame_ = frame;
-      converter_.ReadParameters(dataset);
 
-      type_ = Type_OrthancInstance;
-      return true;
-    }
-    else
-    {
-      return false;
-    }
+    return true;
   }
 
   
   const std::string Slice::GetOrthancInstanceId() const
   {
-    if (type_ != Type_OrthancInstance)
+    if (type_ == Type_OrthancDecodableFrame ||
+        type_ == Type_OrthancRawFrame)
+    {
+      return orthancInstanceId_;
+    }
+    else
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-        
-    return orthancInstanceId_;
+    }   
   }