diff Framework/Radiography/RadiographyScene.cpp @ 430:b85f635f1eb5 am-vsol-upgrade

added serialization for RadiographyScene
author am@osimis.io
date Thu, 29 Nov 2018 15:11:19 +0100
parents 751fb354149e 3f9017db1738
children 26b90b110719
line wrap: on
line diff
--- a/Framework/Radiography/RadiographyScene.cpp	Wed Nov 28 10:46:32 2018 +0100
+++ b/Framework/Radiography/RadiographyScene.cpp	Thu Nov 29 15:11:19 2018 +0100
@@ -21,6 +21,9 @@
 
 #include "RadiographyScene.h"
 
+#include "RadiographyAlphaLayer.h"
+#include "RadiographyDicomLayer.h"
+#include "RadiographyTextLayer.h"
 #include "../Toolbox/DicomFrameConverter.h"
 
 #include <Core/Images/Image.h>
@@ -121,288 +124,6 @@
     }
   }
 
-
-
-  class RadiographyScene::AlphaLayer : public RadiographyLayer
-  {
-  private:
-    const RadiographyScene&                scene_;
-    std::auto_ptr<Orthanc::ImageAccessor>  alpha_;      // Grayscale8
-    bool                                   useWindowing_;
-    float                                  foreground_;
-
-  public:
-    AlphaLayer(const RadiographyScene& scene) :
-      scene_(scene),
-      useWindowing_(true),
-      foreground_(0)
-    {
-    }
-
-
-    void SetForegroundValue(float foreground)
-    {
-      useWindowing_ = false;
-      foreground_ = foreground;
-    }
-
-
-    void SetAlpha(Orthanc::ImageAccessor* image)
-    {
-      std::auto_ptr<Orthanc::ImageAccessor> raii(image);
-
-      if (image == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-      }
-
-      if (image->GetFormat() != Orthanc::PixelFormat_Grayscale8)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
-      }
-
-      SetSize(image->GetWidth(), image->GetHeight());
-      alpha_ = raii;
-    }
-
-
-    void LoadText(const Orthanc::Font& font,
-                  const std::string& utf8)
-    {
-      SetAlpha(font.RenderAlpha(utf8));
-    }
-
-
-    virtual bool GetDefaultWindowing(float& center,
-                                     float& width) const
-    {
-      return false;
-    }
-
-
-    virtual void Render(Orthanc::ImageAccessor& buffer,
-                        const AffineTransform2D& viewTransform,
-                        ImageInterpolation interpolation) const
-    {
-      if (alpha_.get() == NULL)
-      {
-        return;
-      }
-
-      if (buffer.GetFormat() != Orthanc::PixelFormat_Float32)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
-      }
-
-      unsigned int cropX, cropY, cropWidth, cropHeight;
-      GetCrop(cropX, cropY, cropWidth, cropHeight);
-
-      const AffineTransform2D t = AffineTransform2D::Combine(
-            viewTransform, GetTransform(),
-            AffineTransform2D::CreateOffset(cropX, cropY));
-
-      Orthanc::ImageAccessor cropped;
-      alpha_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight);
-
-      Orthanc::Image tmp(Orthanc::PixelFormat_Grayscale8, buffer.GetWidth(), buffer.GetHeight(), false);
-      
-      t.Apply(tmp, cropped, interpolation, true /* clear */);
-
-      // Blit
-      const unsigned int width = buffer.GetWidth();
-      const unsigned int height = buffer.GetHeight();
-
-      float value = foreground_;
-
-      if (useWindowing_)
-      {
-        float center, width;
-        if (scene_.GetWindowing(center, width))
-        {
-          value = center + width / 2.0f;
-        }
-      }
-
-      for (unsigned int y = 0; y < height; y++)
-      {
-        float *q = reinterpret_cast<float*>(buffer.GetRow(y));
-        const uint8_t *p = reinterpret_cast<uint8_t*>(tmp.GetRow(y));
-
-        for (unsigned int x = 0; x < width; x++, p++, q++)
-        {
-          float a = static_cast<float>(*p) / 255.0f;
-
-          *q = (a * value + (1.0f - a) * (*q));
-        }
-      }
-    }
-
-
-    virtual bool GetRange(float& minValue,
-                          float& maxValue) const
-    {
-      if (useWindowing_)
-      {
-        return false;
-      }
-      else
-      {
-        minValue = 0;
-        maxValue = 0;
-
-        if (foreground_ < 0)
-        {
-          minValue = foreground_;
-        }
-
-        if (foreground_ > 0)
-        {
-          maxValue = foreground_;
-        }
-
-        return true;
-      }
-    }
-  };
-
-
-
-  class RadiographyScene::DicomLayer : public RadiographyLayer
-  {
-  private:
-    std::auto_ptr<Orthanc::ImageAccessor>  source_;  // Content of PixelData
-    std::auto_ptr<DicomFrameConverter>     converter_;
-    std::auto_ptr<Orthanc::ImageAccessor>  converted_;  // Float32
-
-    static OrthancPlugins::DicomTag  ConvertTag(const Orthanc::DicomTag& tag)
-    {
-      return OrthancPlugins::DicomTag(tag.GetGroup(), tag.GetElement());
-    }
-
-
-    void ApplyConverter()
-    {
-      if (source_.get() != NULL &&
-          converter_.get() != NULL)
-      {
-        converted_.reset(converter_->ConvertFrame(*source_));
-      }
-    }
-
-  public:
-    void SetDicomTags(const OrthancPlugins::FullOrthancDataset& dataset)
-    {
-      converter_.reset(new DicomFrameConverter);
-      converter_->ReadParameters(dataset);
-      ApplyConverter();
-
-      std::string tmp;
-      Vector pixelSpacing;
-
-      if (dataset.GetStringValue(tmp, ConvertTag(Orthanc::DICOM_TAG_PIXEL_SPACING)) &&
-          LinearAlgebra::ParseVector(pixelSpacing, tmp) &&
-          pixelSpacing.size() == 2)
-      {
-        SetPixelSpacing(pixelSpacing[0], pixelSpacing[1]);
-      }
-
-      //SetPan(-0.5 * GetPixelSpacingX(), -0.5 * GetPixelSpacingY());
-      
-      OrthancPlugins::DicomDatasetReader reader(dataset);
-
-      unsigned int width, height;
-      if (!reader.GetUnsignedIntegerValue(width, ConvertTag(Orthanc::DICOM_TAG_COLUMNS)) ||
-          !reader.GetUnsignedIntegerValue(height, ConvertTag(Orthanc::DICOM_TAG_ROWS)))
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-      }
-      else
-      {
-        SetSize(width, height);
-      }
-    }
-
-
-    void SetSourceImage(Orthanc::ImageAccessor* image)   // Takes ownership
-    {
-      std::auto_ptr<Orthanc::ImageAccessor> raii(image);
-
-      if (image == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-      }
-
-      SetSize(image->GetWidth(), image->GetHeight());
-
-      source_ = raii;
-      ApplyConverter();
-    }
-
-
-    virtual void Render(Orthanc::ImageAccessor& buffer,
-                        const AffineTransform2D& viewTransform,
-                        ImageInterpolation interpolation) const
-    {
-      if (converted_.get() != NULL)
-      {
-        if (converted_->GetFormat() != Orthanc::PixelFormat_Float32)
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-        }
-
-        unsigned int cropX, cropY, cropWidth, cropHeight;
-        GetCrop(cropX, cropY, cropWidth, cropHeight);
-
-        AffineTransform2D t = AffineTransform2D::Combine(
-              viewTransform, GetTransform(),
-              AffineTransform2D::CreateOffset(cropX, cropY));
-
-        Orthanc::ImageAccessor cropped;
-        converted_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight);
-        
-        t.Apply(buffer, cropped, interpolation, false);
-      }
-    }
-
-
-    virtual bool GetDefaultWindowing(float& center,
-                                     float& width) const
-    {
-      if (converter_.get() != NULL &&
-          converter_->HasDefaultWindow())
-      {
-        center = static_cast<float>(converter_->GetDefaultWindowCenter());
-        width = static_cast<float>(converter_->GetDefaultWindowWidth());
-        return true;
-      }
-      else
-      {
-        return false;
-      }
-    }
-
-
-    virtual bool GetRange(float& minValue,
-                          float& maxValue) const
-    {
-      if (converted_.get() != NULL)
-      {
-        if (converted_->GetFormat() != Orthanc::PixelFormat_Float32)
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-        }
-
-        Orthanc::ImageProcessing::GetMinMaxFloatValue(minValue, maxValue, *converted_);
-        return true;
-      }
-      else
-      {
-        return false;
-      }
-    }
-  };
-
-
   RadiographyLayer& RadiographyScene::RegisterLayer(RadiographyLayer* layer)
   {
     if (layer == NULL)
@@ -418,8 +139,8 @@
     raii->SetIndex(index);
     layers_[index] = raii.release();
 
-    EmitMessage(GeometryChangedMessage(*this));
-    EmitMessage(ContentChangedMessage(*this));
+    EmitMessage(GeometryChangedMessage(*this, *layer));
+    EmitMessage(ContentChangedMessage(*this, *layer));
 
     return *layer;
   }
@@ -445,6 +166,14 @@
     }
   }
 
+  void RadiographyScene::GetLayersIndexes(std::vector<size_t>& output) const
+  {
+    for (Layers::const_iterator it = layers_.begin(); it != layers_.end(); it++)
+    {
+      output.push_back(it->first);
+    }
+  }
+
   void RadiographyScene::RemoveLayer(size_t layerIndex)
   {
     LOG(INFO) << "Removing layer: " << layerIndex;
@@ -459,13 +188,14 @@
     LOG(INFO) << "Removing layer, there are now : " << countLayers_ << " layers";
   }
 
-  RadiographyLayer& RadiographyScene::GetLayer(size_t layerIndex)
+  const RadiographyLayer& RadiographyScene::GetLayer(size_t layerIndex) const
   {
     if (layerIndex > countLayers_)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
-    return *(layers_[layerIndex]);
+
+    return *(layers_.at(layerIndex));
   }
 
   bool RadiographyScene::GetWindowing(float& center,
@@ -505,17 +235,23 @@
 
 
   RadiographyLayer& RadiographyScene::LoadText(const Orthanc::Font& font,
-                                               const std::string& utf8)
+                                               const std::string& utf8,
+                                               RadiographyLayer::Geometry* geometry)
   {
-    std::auto_ptr<AlphaLayer>  alpha(new AlphaLayer(*this));
+    std::auto_ptr<RadiographyTextLayer>  alpha(new RadiographyTextLayer(*this));
     alpha->LoadText(font, utf8);
+    if (geometry != NULL)
+    {
+      alpha->SetGeometry(*geometry);
+    }
 
     return RegisterLayer(alpha.release());
   }
 
 
   RadiographyLayer& RadiographyScene::LoadTestBlock(unsigned int width,
-                                                    unsigned int height)
+                                                    unsigned int height,
+                                                    RadiographyLayer::Geometry* geometry)
   {
     std::auto_ptr<Orthanc::Image>  block(new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, width, height, false));
 
@@ -538,19 +274,34 @@
       Orthanc::ImageProcessing::Set(region, color);
     }
 
-    std::auto_ptr<AlphaLayer>  alpha(new AlphaLayer(*this));
-    alpha->SetAlpha(block.release());
+    return LoadAlphaBitmap(block.release(), geometry);
+  }
+
+  RadiographyLayer& RadiographyScene::LoadAlphaBitmap(Orthanc::ImageAccessor* bitmap, RadiographyLayer::Geometry *geometry)
+  {
+    std::auto_ptr<RadiographyAlphaLayer>  alpha(new RadiographyAlphaLayer(*this));
+    alpha->SetAlpha(bitmap);
+    if (geometry != NULL)
+    {
+      alpha->SetGeometry(*geometry);
+    }
 
     return RegisterLayer(alpha.release());
   }
 
-
   RadiographyLayer& RadiographyScene::LoadDicomFrame(OrthancApiClient& orthanc,
                                                      const std::string& instance,
                                                      unsigned int frame,
-                                                     bool httpCompression)
+                                                     bool httpCompression,
+                                                     RadiographyLayer::Geometry* geometry)
   {
-    RadiographyLayer& layer = RegisterLayer(new DicomLayer);
+    RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer));
+    layer.SetInstance(instance, frame);
+
+    if (geometry != NULL)
+    {
+      layer.SetGeometry(*geometry);
+    }
 
     {
       IWebService::HttpHeaders headers;
@@ -588,7 +339,7 @@
 
   RadiographyLayer& RadiographyScene::LoadDicomWebFrame(IWebService& web)
   {
-    RadiographyLayer& layer = RegisterLayer(new DicomLayer);
+    RadiographyLayer& layer = RegisterLayer(new RadiographyDicomLayer);
 
 
     return layer;
@@ -610,7 +361,7 @@
       assert(layer->second != NULL);
 
       OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer(), message.GetAnswerSize());
-      dynamic_cast<DicomLayer*>(layer->second)->SetDicomTags(dicom);
+      dynamic_cast<RadiographyDicomLayer*>(layer->second)->SetDicomTags(dicom);
 
       float c, w;
       if (!hasWindowing_ &&
@@ -621,7 +372,7 @@
         windowingWidth_ = w;
       }
 
-      EmitMessage(GeometryChangedMessage(*this));
+      EmitMessage(GeometryChangedMessage(*this, *(layer->second)));
     }
   }
 
@@ -646,9 +397,9 @@
 
       std::auto_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader);
       reader->ReadFromMemory(content);
-      dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(reader.release());
+      dynamic_cast<RadiographyDicomLayer*>(layer->second)->SetSourceImage(reader.release());
 
-      EmitMessage(ContentChangedMessage(*this));
+      EmitMessage(ContentChangedMessage(*this, *(layer->second)));
     }
   }
 
@@ -672,7 +423,7 @@
                                 const AffineTransform2D& viewTransform,
                                 ImageInterpolation interpolation) const
   {
-    Orthanc::ImageProcessing::Set(buffer, 0);
+    Orthanc::ImageProcessing::Set(buffer, 0); // TODO: get background color (depending on inverted state)
 
     // Render layers in the background-to-foreground order
     for (size_t index = 0; index < countLayers_; index++)
@@ -770,7 +521,7 @@
   {
     Json::Value createDicomRequestContent;
 
-    Export(createDicomRequestContent, dicom, pixelSpacingX, pixelSpacingY, invert, interpolation, usePam);
+    ExportToCreateDicomRequest(createDicomRequestContent, dicom, pixelSpacingX, pixelSpacingY, invert, interpolation, usePam);
 
     if (!parentOrthancId.empty())
     {
@@ -786,7 +537,7 @@
 
   // Export using PAM is faster than using PNG, but requires Orthanc
   // core >= 1.4.3
-  void RadiographyScene::Export(Json::Value& createDicomRequestContent,
+  void RadiographyScene::ExportToCreateDicomRequest(Json::Value& createDicomRequestContent,
                                 const Orthanc::DicomMap& dicom,
                                 double pixelSpacingX,
                                 double pixelSpacingY,