changeset 481:159a465e27bd am-touch-events

reworked RadiographyScene export to export to an Orthanc::Image too
author am@osimis.io
date Thu, 14 Feb 2019 16:23:59 +0100
parents 2f6ecb5037ea
children 29fc066b6f65
files Framework/Radiography/RadiographyMaskLayer.cpp Framework/Radiography/RadiographyMaskLayer.h Framework/Radiography/RadiographyScene.cpp Framework/Radiography/RadiographyScene.h Framework/Radiography/RadiographySceneReader.cpp Framework/Radiography/RadiographySceneReader.h Framework/Radiography/RadiographySceneWriter.cpp Framework/Radiography/RadiographySceneWriter.h
diffstat 8 files changed, 117 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Radiography/RadiographyMaskLayer.cpp	Thu Feb 14 10:18:02 2019 +0100
+++ b/Framework/Radiography/RadiographyMaskLayer.cpp	Thu Feb 14 16:23:59 2019 +0100
@@ -68,6 +68,11 @@
     }
   }
 
+  std::string RadiographyMaskLayer::GetInstanceId() const
+  {
+    return dicomLayer_.GetInstanceId();
+  }
+
   void RadiographyMaskLayer::SetCorner(const MaskPoint& corner, size_t index)
   {
     if (index < corners_.size())
--- a/Framework/Radiography/RadiographyMaskLayer.h	Thu Feb 14 10:18:02 2019 +0100
+++ b/Framework/Radiography/RadiographyMaskLayer.h	Thu Feb 14 16:23:59 2019 +0100
@@ -62,10 +62,22 @@
     void SetCorners(const std::vector<MaskPoint>& corners);
     void SetCorner(const MaskPoint& corner, size_t index);
 
+    const std::vector<MaskPoint>& GetCorners() const
+    {
+      return corners_;
+    }
+
+    float GetForeground() const
+    {
+      return foreground_;
+    }
+
     virtual void Render(Orthanc::ImageAccessor& buffer,
                         const AffineTransform2D& viewTransform,
                         ImageInterpolation interpolation) const;
 
+    std::string GetInstanceId() const;
+
     virtual size_t GetControlPointCount() const
     {
       return corners_.size();
--- a/Framework/Radiography/RadiographyScene.cpp	Thu Feb 14 10:18:02 2019 +0100
+++ b/Framework/Radiography/RadiographyScene.cpp	Thu Feb 14 16:23:59 2019 +0100
@@ -539,41 +539,11 @@
     }
   }
 
-
-  void RadiographyScene::ExportDicom(OrthancApiClient& orthanc,
-                                     const Orthanc::DicomMap& dicom,
-                                     const std::string& parentOrthancId,
-                                     double pixelSpacingX,
-                                     double pixelSpacingY,
-                                     bool invert,
-                                     ImageInterpolation interpolation,
-                                     bool usePam)
-  {
-    Json::Value createDicomRequestContent;
-
-    ExportToCreateDicomRequest(createDicomRequestContent, dicom, pixelSpacingX, pixelSpacingY, invert, interpolation, usePam);
-
-    if (!parentOrthancId.empty())
-    {
-      createDicomRequestContent["Parent"] = parentOrthancId;
-    }
-
-    orthanc.PostJsonAsyncExpectJson(
-          "/tools/create-dicom", createDicomRequestContent,
-          new Callable<RadiographyScene, OrthancApiClient::JsonResponseReadyMessage>
-          (*this, &RadiographyScene::OnDicomExported),
-          NULL, NULL);
-  }
-
-  // Export using PAM is faster than using PNG, but requires Orthanc
-  // core >= 1.4.3
-  void RadiographyScene::ExportToCreateDicomRequest(Json::Value& createDicomRequestContent,
-                                const Orthanc::DicomMap& dicom,
-                                double pixelSpacingX,
-                                double pixelSpacingY,
-                                bool invert,
-                                ImageInterpolation interpolation,
-                                bool usePam)
+  Orthanc::Image* RadiographyScene::ExportToImage(double pixelSpacingX,
+                                                  double pixelSpacingY,
+                                                  ImageInterpolation interpolation,
+                                                  bool invert,
+                                                  int64_t maxValue /* for inversion */)
   {
     if (pixelSpacingX <= 0 ||
         pixelSpacingY <= 0)
@@ -606,9 +576,31 @@
 
     Render(layers, view, interpolation);
 
-    Orthanc::Image rendered(Orthanc::PixelFormat_Grayscale16,
-                            layers.GetWidth(), layers.GetHeight(), false);
-    Orthanc::ImageProcessing::Convert(rendered, layers);
+    std::auto_ptr<Orthanc::Image> rendered(new Orthanc::Image(Orthanc::PixelFormat_Grayscale16,
+                                                               layers.GetWidth(), layers.GetHeight(), false));
+
+    Orthanc::ImageProcessing::Convert(*rendered, layers);
+    if (invert)
+      Orthanc::ImageProcessing::Invert(*rendered, maxValue);
+
+    return rendered.release();
+  }
+
+
+  // Export using PAM is faster than using PNG, but requires Orthanc
+  // core >= 1.4.3
+  void RadiographyScene::ExportDicom(OrthancApiClient& orthanc,
+                                     const Orthanc::DicomMap& dicom,
+                                     const std::string& parentOrthancId,
+                                     double pixelSpacingX,
+                                     double pixelSpacingY,
+                                     bool invert,
+                                     ImageInterpolation interpolation,
+                                     bool usePam)
+  {
+    Json::Value createDicomRequestContent;
+
+    std::auto_ptr<Orthanc::Image> rendered(ExportToImage(pixelSpacingX, pixelSpacingY, interpolation)); // note: we don't invert the image in the pixels data because we'll set the PhotometricDisplayMode correctly in the DICOM tags
 
     std::string base64;
 
@@ -618,12 +610,12 @@
       if (usePam)
       {
         Orthanc::PamWriter writer;
-        writer.WriteToMemory(content, rendered);
+        writer.WriteToMemory(content, *rendered);
       }
       else
       {
         Orthanc::PngWriter writer;
-        writer.WriteToMemory(content, rendered);
+        writer.WriteToMemory(content, *rendered);
       }
 
       Orthanc::Toolbox::EncodeBase64(base64, content);
@@ -680,9 +672,19 @@
     createDicomRequestContent["Content"] = ("data:" +
                                             std::string(usePam ? Orthanc::MIME_PAM : Orthanc::MIME_PNG) +
                                             ";base64," + base64);
+
+    if (!parentOrthancId.empty())
+    {
+      createDicomRequestContent["Parent"] = parentOrthancId;
+    }
+
+    orthanc.PostJsonAsyncExpectJson(
+          "/tools/create-dicom", createDicomRequestContent,
+          new Callable<RadiographyScene, OrthancApiClient::JsonResponseReadyMessage>
+          (*this, &RadiographyScene::OnDicomExported),
+          NULL, NULL);
   }
 
-
   void RadiographyScene::OnDicomExported(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
     LOG(INFO) << "DICOM export was successful: "
--- a/Framework/Radiography/RadiographyScene.h	Thu Feb 14 10:18:02 2019 +0100
+++ b/Framework/Radiography/RadiographyScene.h	Thu Feb 14 16:23:59 2019 +0100
@@ -24,6 +24,7 @@
 #include "RadiographyLayer.h"
 #include "../Toolbox/OrthancApiClient.h"
 #include "Framework/StoneEnumerations.h"
+#include "Core/Images/Image.h"
 
 namespace OrthancStone
 {
@@ -203,13 +204,17 @@
                      ImageInterpolation interpolation,
                      bool usePam);
 
-    // temporary version used by VSOL because we need to send the same request at another url
-    void ExportToCreateDicomRequest(Json::Value& createDicomRequestContent,
-                                    const Orthanc::DicomMap& dicom,
-                                    double pixelSpacingX,
-                                    double pixelSpacingY,
-                                    bool invert,
-                                    ImageInterpolation interpolation,
-                                    bool usePam);
+    Orthanc::Image* ExportToImage(double pixelSpacingX,
+                                  double pixelSpacingY,
+                                  ImageInterpolation interpolation)
+    {
+      ExportToImage(pixelSpacingX, pixelSpacingY, interpolation, false, 0);
+    }
+
+    Orthanc::Image* ExportToImage(double pixelSpacingX,
+                                  double pixelSpacingY,
+                                  ImageInterpolation interpolation,
+                                  bool invert,
+                                  int64_t maxValue /* for inversion */);
   };
 }
--- a/Framework/Radiography/RadiographySceneReader.cpp	Thu Feb 14 10:18:02 2019 +0100
+++ b/Framework/Radiography/RadiographySceneReader.cpp	Thu Feb 14 16:23:59 2019 +0100
@@ -35,6 +35,7 @@
     if (version != 1)
       throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
 
+    RadiographyDicomLayer* dicomLayer = NULL;
     for(size_t layerIndex = 0; layerIndex < input["layers"].size(); layerIndex++)
     {
       const Json::Value& jsonLayer = input["layers"][(int)layerIndex];
@@ -43,7 +44,26 @@
       if (jsonLayer["type"].asString() == "dicom")
       {
         ReadLayerGeometry(geometry, jsonLayer);
-        scene_.LoadDicomFrame(orthancApiClient_, jsonLayer["instanceId"].asString(), jsonLayer["frame"].asUInt(), false, &geometry);
+        dicomLayer = dynamic_cast<RadiographyDicomLayer*>(&(scene_.LoadDicomFrame(orthancApiClient_, jsonLayer["instanceId"].asString(), jsonLayer["frame"].asUInt(), false, &geometry)));
+      }
+      else if (jsonLayer["type"].asString() == "mask")
+      {
+        if (dicomLayer == NULL)
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); // we always assumed the dicom layer was read before the mask
+        }
+        ReadLayerGeometry(geometry, jsonLayer);
+
+        float foreground = jsonLayer["foreground"].asFloat();
+        std::vector<MaskPoint> corners;
+        for (size_t i = 0; i < jsonLayer["corners"].size(); i++)
+        {
+          MaskPoint corner(jsonLayer["corners"][(int)i]["x"].asUInt(),
+              jsonLayer["corners"][(int)i]["y"].asUInt());
+          corners.push_back(corner);
+        }
+
+        scene_.LoadMask(corners, *dicomLayer, foreground, &geometry);
       }
       else if (jsonLayer["type"].asString() == "text")
       {
--- a/Framework/Radiography/RadiographySceneReader.h	Thu Feb 14 10:18:02 2019 +0100
+++ b/Framework/Radiography/RadiographySceneReader.h	Thu Feb 14 16:23:59 2019 +0100
@@ -24,6 +24,7 @@
 #include "RadiographyScene.h"
 #include "RadiographyAlphaLayer.h"
 #include "RadiographyDicomLayer.h"
+#include "RadiographyMaskLayer.h"
 #include "RadiographyTextLayer.h"
 #include <json/value.h>
 #include <Core/Images/FontRegistry.h>
--- a/Framework/Radiography/RadiographySceneWriter.cpp	Thu Feb 14 10:18:02 2019 +0100
+++ b/Framework/Radiography/RadiographySceneWriter.cpp	Thu Feb 14 16:23:59 2019 +0100
@@ -57,6 +57,22 @@
     output["fontName"] = layer.GetFontName();
   }
 
+  void RadiographySceneWriter::WriteLayer(Json::Value& output, const RadiographyMaskLayer& layer)
+  {
+    output["type"] = "mask";
+    output["instanceId"] = layer.GetInstanceId(); // the dicom layer it's being linked to
+    output["foreground"] = layer.GetForeground();
+    output["corners"] = Json::arrayValue;
+    const std::vector<MaskPoint>& corners = layer.GetCorners();
+    for (size_t i = 0; i < corners.size(); i++)
+    {
+      Json::Value corner;
+      corner["x"] = corners[i].x;
+      corner["y"] = corners[i].y;
+      output["corners"].append(corner);
+    }
+  }
+
   void RadiographySceneWriter::WriteLayer(Json::Value& output, const RadiographyAlphaLayer& layer)
   {
     output["type"] = "alpha";
@@ -128,6 +144,10 @@
     {
       WriteLayer(output, dynamic_cast<const RadiographyAlphaLayer&>(layer));
     }
+    else if (dynamic_cast<const RadiographyMaskLayer*>(&layer) != NULL)
+    {
+      WriteLayer(output, dynamic_cast<const RadiographyMaskLayer&>(layer));
+    }
     else
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
--- a/Framework/Radiography/RadiographySceneWriter.h	Thu Feb 14 10:18:02 2019 +0100
+++ b/Framework/Radiography/RadiographySceneWriter.h	Thu Feb 14 16:23:59 2019 +0100
@@ -25,6 +25,7 @@
 #include "RadiographyAlphaLayer.h"
 #include "RadiographyDicomLayer.h"
 #include "RadiographyTextLayer.h"
+#include "RadiographyMaskLayer.h"
 #include <json/value.h>
 
 namespace OrthancStone
@@ -46,5 +47,6 @@
     void WriteLayer(Json::Value& output, const RadiographyDicomLayer& layer);
     void WriteLayer(Json::Value& output, const RadiographyTextLayer& layer);
     void WriteLayer(Json::Value& output, const RadiographyAlphaLayer& layer);
+    void WriteLayer(Json::Value& output, const RadiographyMaskLayer& layer);
   };
 }