diff Framework/Radiography/RadiographyScene.cpp @ 421:f87f28624b96 cache-in-radiography

tentative to make SmartLoader and RadiographyScene work together (not really working)
author am@osimis.io
date Tue, 20 Nov 2018 16:35:29 +0100
parents c23df8b3433b
children
line wrap: on
line diff
--- a/Framework/Radiography/RadiographyScene.cpp	Mon Nov 19 12:45:37 2018 +0100
+++ b/Framework/Radiography/RadiographyScene.cpp	Tue Nov 20 16:35:29 2018 +0100
@@ -55,7 +55,7 @@
     }
   }
 
-      
+
   RadiographyScene::LayerAccessor::LayerAccessor(RadiographyScene& scene,
                                                  double x,
                                                  double y) :
@@ -65,7 +65,7 @@
     if (scene.LookupLayer(index_, x, y))
     {
       Layers::iterator layer = scene.layers_.find(index_);
-          
+
       if (layer == scene.layers_.end())
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
@@ -119,7 +119,7 @@
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
     }
-  }    
+  }
 
 
 
@@ -145,12 +145,12 @@
       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);
@@ -170,7 +170,7 @@
                   const std::string& utf8)
     {
       SetAlpha(font.RenderAlpha(utf8));
-    }                   
+    }
 
 
     virtual bool GetDefaultWindowing(float& center,
@@ -178,7 +178,7 @@
     {
       return false;
     }
-      
+
 
     virtual void Render(Orthanc::ImageAccessor& buffer,
                         const AffineTransform2D& viewTransform,
@@ -188,7 +188,7 @@
       {
         return;
       }
-        
+
       if (buffer.GetFormat() != Orthanc::PixelFormat_Float32)
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
@@ -198,12 +198,12 @@
       GetCrop(cropX, cropY, cropWidth, cropHeight);
 
       const AffineTransform2D t = AffineTransform2D::Combine(
-        viewTransform, GetTransform(),
-        AffineTransform2D::CreateOffset(cropX, cropY));
+            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 */);
@@ -213,7 +213,7 @@
       const unsigned int height = buffer.GetHeight();
 
       float value = foreground_;
-        
+
       if (useWindowing_)
       {
         float center, width;
@@ -222,7 +222,7 @@
           value = center + width / 2.0f;
         }
       }
-        
+
       for (unsigned int y = 0; y < height; y++)
       {
         float *q = reinterpret_cast<float*>(buffer.GetRow(y));
@@ -231,13 +231,13 @@
         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
     {
@@ -264,13 +264,13 @@
       }
     }
   };
-    
-    
+
+
 
   class RadiographyScene::DicomLayer : public RadiographyLayer
   {
   private:
-    std::auto_ptr<Orthanc::ImageAccessor>  source_;  // Content of PixelData
+    boost::shared_ptr<Orthanc::ImageAccessor>  source_;  // Content of PixelData
     std::auto_ptr<DicomFrameConverter>     converter_;
     std::auto_ptr<Orthanc::ImageAccessor>  converted_;  // Float32
 
@@ -278,7 +278,7 @@
     {
       return OrthancPlugins::DicomTag(tag.GetGroup(), tag.GetElement());
     }
-      
+
 
     void ApplyConverter()
     {
@@ -288,7 +288,7 @@
         converted_.reset(converter_->ConvertFrame(*source_));
       }
     }
-      
+
   public:
     void SetDicomTags(const OrthancPlugins::FullOrthancDataset& dataset)
     {
@@ -298,7 +298,7 @@
 
       std::string tmp;
       Vector pixelSpacing;
-        
+
       if (dataset.GetStringValue(tmp, ConvertTag(Orthanc::DICOM_TAG_PIXEL_SPACING)) &&
           LinearAlgebra::ParseVector(pixelSpacing, tmp) &&
           pixelSpacing.size() == 2)
@@ -322,23 +322,21 @@
       }
     }
 
-      
-    void SetSourceImage(Orthanc::ImageAccessor* image)   // Takes ownership
+
+    void SetSourceImage(boost::shared_ptr<Orthanc::ImageAccessor> image)
     {
-      std::auto_ptr<Orthanc::ImageAccessor> raii(image);
-        
-      if (image == NULL)
+      if (image.get() == NULL)
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
       }
 
       SetSize(image->GetWidth(), image->GetHeight());
-        
-      source_ = raii;
+
+      source_ = image;
       ApplyConverter();
     }
 
-      
+
     virtual void Render(Orthanc::ImageAccessor& buffer,
                         const AffineTransform2D& viewTransform,
                         ImageInterpolation interpolation) const
@@ -354,8 +352,8 @@
         GetCrop(cropX, cropY, cropWidth, cropHeight);
 
         AffineTransform2D t = AffineTransform2D::Combine(
-          viewTransform, GetTransform(),
-          AffineTransform2D::CreateOffset(cropX, cropY));
+              viewTransform, GetTransform(),
+              AffineTransform2D::CreateOffset(cropX, cropY));
 
         Orthanc::ImageAccessor cropped;
         converted_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight);
@@ -411,7 +409,7 @@
     }
 
     std::auto_ptr<RadiographyLayer> raii(layer);
-      
+
     size_t index = countLayers_++;
     raii->SetIndex(index);
     layers_[index] = raii.release();
@@ -421,7 +419,7 @@
 
     return *layer;
   }
-    
+
 
   RadiographyScene::RadiographyScene(MessageBroker& broker) :
     IObserver(broker),
@@ -489,7 +487,7 @@
     return RegisterLayer(alpha.release());
   }
 
-    
+
   RadiographyLayer& RadiographyScene::LoadTestBlock(unsigned int width,
                                                     unsigned int height)
   {
@@ -520,7 +518,7 @@
     return RegisterLayer(alpha.release());
   }
 
-    
+
   RadiographyLayer& RadiographyScene::LoadDicomFrame(OrthancApiClient& orthanc,
                                                      const std::string& instance,
                                                      unsigned int frame,
@@ -531,12 +529,12 @@
     {
       IWebService::HttpHeaders headers;
       std::string uri = "/instances/" + instance + "/tags";
-        
+
       orthanc.GetBinaryAsync(
-        uri, headers,
-        new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage>
-        (*this, &RadiographyScene::OnTagsReceived), NULL,
-        new Orthanc::SingleValueObject<size_t>(layer.GetIndex()));
+            uri, headers,
+            new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage>
+            (*this, &RadiographyScene::OnTagsReceived), NULL,
+            new Orthanc::SingleValueObject<size_t>(layer.GetIndex()));
     }
 
     {
@@ -547,15 +545,15 @@
       {
         headers["Accept-Encoding"] = "gzip";
       }
-        
+
       std::string uri = ("/instances/" + instance + "/frames/" +
                          boost::lexical_cast<std::string>(frame) + "/image-uint16");
-        
+
       orthanc.GetBinaryAsync(
-        uri, headers,
-        new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage>
-        (*this, &RadiographyScene::OnFrameReceived), NULL,
-        new Orthanc::SingleValueObject<size_t>(layer.GetIndex()));
+            uri, headers,
+            new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage>
+            (*this, &RadiographyScene::OnFrameReceived), NULL,
+            new Orthanc::SingleValueObject<size_t>(layer.GetIndex()));
     }
 
     return layer;
@@ -566,25 +564,67 @@
   {
     RadiographyLayer& layer = RegisterLayer(new DicomLayer);
 
-      
+
+    return layer;
+  }
+
+  RadiographyLayer& RadiographyScene::SetFrame(IVolumeSlicer* slice)
+  {
+    RadiographyLayer& layer = RegisterLayer(new DicomLayer);
+    layersIndexBySlice_[slice] = layer.GetIndex();
+
+    slice->RegisterObserverCallback(new Callable<RadiographyScene, IVolumeSlicer::TagsReadyMessage>
+                                    (*this, &RadiographyScene::OnTagsReady));
+    slice->RegisterObserverCallback(new Callable<RadiographyScene, IVolumeSlicer::FrameReadyMessage>
+                                    (*this, &RadiographyScene::OnImageReady));
+
+    // TODO: register failures
+
     return layer;
   }
 
+  void RadiographyScene::OnTagsReady(const IVolumeSlicer::TagsReadyMessage &message)
+  {
+    size_t layerIndex = layersIndexBySlice_[&(message.GetOrigin())];
+    Layers::iterator layer = layers_.find(layerIndex);
 
-    
+    if (layer != layers_.end())
+    {
+      assert(layer->second != NULL);
+
+      const OrthancPlugins::FullOrthancDataset& dicom = message.GetDicomTags();
+      dynamic_cast<DicomLayer*>(layer->second)->SetDicomTags(dicom);
+
+      float c, w;
+      if (!hasWindowing_ &&
+          layer->second->GetDefaultWindowing(c, w))
+      {
+        hasWindowing_ = true;
+        windowingCenter_ = c;
+        windowingWidth_ = w;
+      }
+
+      EmitMessage(GeometryChangedMessage(*this));
+
+      CoordinateSystem3D dummy;
+      message.GetOrigin().ScheduleLayerCreation(dummy);
+    }
+
+  }
+
   void RadiographyScene::OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message)
   {
     size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>
-      (message.GetPayload()).GetValue();
+        (message.GetPayload()).GetValue();
 
     LOG(INFO) << "JSON received: " << message.GetUri().c_str()
               << " (" << message.GetAnswerSize() << " bytes) for layer " << index;
-      
+
     Layers::iterator layer = layers_.find(index);
     if (layer != layers_.end())
     {
       assert(layer->second != NULL);
-        
+
       OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer(), message.GetAnswerSize());
       dynamic_cast<DicomLayer*>(layer->second)->SetDicomTags(dicom);
 
@@ -600,15 +640,30 @@
       EmitMessage(GeometryChangedMessage(*this));
     }
   }
-    
+
+
+  void RadiographyScene::OnImageReady(const IVolumeSlicer::FrameReadyMessage &message)
+  {
+    size_t layerIndex = layersIndexBySlice_[&(message.GetOrigin())];
+    Layers::iterator layer = layers_.find(layerIndex);
+
+    if (layer != layers_.end())
+    {
+      assert(layer->second != NULL);
+
+      dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(message.GetImage());
+
+      EmitMessage(ContentChangedMessage(*this));
+    }
+  }
 
   void RadiographyScene::OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message)
   {
     size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue();
-      
+
     LOG(INFO) << "DICOM frame received: " << message.GetUri().c_str()
               << " (" << message.GetAnswerSize() << " bytes) for layer " << index;
-      
+
     Layers::iterator layer = layers_.find(index);
     if (layer != layers_.end())
     {
@@ -619,10 +674,10 @@
       {
         content.assign(reinterpret_cast<const char*>(message.GetAnswer()), message.GetAnswerSize());
       }
-        
-      std::auto_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader);
+
+      boost::shared_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader);
       reader->ReadFromMemory(content);
-      dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(reader.release());
+      dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(reader);
 
       EmitMessage(ContentChangedMessage(*this));
     }
@@ -642,7 +697,7 @@
 
     return extent;
   }
-    
+
 
   void RadiographyScene::Render(Orthanc::ImageAccessor& buffer,
                                 const AffineTransform2D& viewTransform,
@@ -685,13 +740,13 @@
     return false;
   }
 
-    
+
   void RadiographyScene::DrawBorder(CairoContext& context,
                                     unsigned int layer,
                                     double zoom)
   {
     Layers::const_iterator found = layers_.find(layer);
-        
+
     if (found != layers_.end())
     {
       context.SetSourceColor(255, 0, 0);
@@ -704,7 +759,7 @@
                                   float& maxValue) const
   {
     bool first = true;
-      
+
     for (Layers::const_iterator it = layers_.begin();
          it != layers_.end(); it++)
     {
@@ -750,7 +805,7 @@
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
-      
+
     LOG(INFO) << "Exporting DICOM";
 
     Extent2D extent = GetSceneExtent();
@@ -768,9 +823,9 @@
                           static_cast<unsigned int>(h), false);
 
     AffineTransform2D view = AffineTransform2D::Combine(
-      AffineTransform2D::CreateScaling(1.0 / pixelSpacingX, 1.0 / pixelSpacingY),
-      AffineTransform2D::CreateOffset(-extent.GetX1(), -extent.GetY1()));
-      
+          AffineTransform2D::CreateScaling(1.0 / pixelSpacingX, 1.0 / pixelSpacingY),
+          AffineTransform2D::CreateOffset(-extent.GetX1(), -extent.GetY1()));
+
     Render(layers, view, interpolation);
 
     Orthanc::Image rendered(Orthanc::PixelFormat_Grayscale16,
@@ -801,9 +856,9 @@
 
     Json::Value json = Json::objectValue;
     json["Tags"] = Json::objectValue;
-           
+
     for (std::set<Orthanc::DicomTag>::const_iterator
-           tag = tags.begin(); tag != tags.end(); ++tag)
+         tag = tags.begin(); tag != tags.end(); ++tag)
     {
       const Orthanc::DicomValue& value = dicom.GetValue(*tag);
       if (!value.IsNull() &&
@@ -814,7 +869,7 @@
     }
 
     json["Tags"][Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION.Format()] =
-      (invert ? "MONOCHROME1" : "MONOCHROME2");
+        (invert ? "MONOCHROME1" : "MONOCHROME2");
 
     // WARNING: The order of PixelSpacing is Y/X. We use "%0.8f" to
     // avoid floating-point numbers to grow over 16 characters,
@@ -822,17 +877,17 @@
     // ("dciodvfy" would complain).
     char buf[32];
     sprintf(buf, "%0.8f\\%0.8f", pixelSpacingY, pixelSpacingX);
-      
+
     json["Tags"][Orthanc::DICOM_TAG_PIXEL_SPACING.Format()] = buf;
 
     float center, width;
     if (GetWindowing(center, width))
     {
       json["Tags"][Orthanc::DICOM_TAG_WINDOW_CENTER.Format()] =
-        boost::lexical_cast<std::string>(boost::math::iround(center));
+          boost::lexical_cast<std::string>(boost::math::iround(center));
 
       json["Tags"][Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()] =
-        boost::lexical_cast<std::string>(boost::math::iround(width));
+          boost::lexical_cast<std::string>(boost::math::iround(width));
     }
 
     // This is Data URI scheme: https://en.wikipedia.org/wiki/Data_URI_scheme
@@ -841,10 +896,10 @@
                        ";base64," + base64);
 
     orthanc.PostJsonAsyncExpectJson(
-      "/tools/create-dicom", json,
-      new Callable<RadiographyScene, OrthancApiClient::JsonResponseReadyMessage>
-      (*this, &RadiographyScene::OnDicomExported),
-      NULL, NULL);
+          "/tools/create-dicom", json,
+          new Callable<RadiographyScene, OrthancApiClient::JsonResponseReadyMessage>
+          (*this, &RadiographyScene::OnDicomExported),
+          NULL, NULL);
   }
 
 
@@ -861,7 +916,7 @@
 
     const IWebService::HttpHeaders& h = message.GetAnswerHttpHeaders();
     for (IWebService::HttpHeaders::const_iterator
-           it = h.begin(); it != h.end(); ++it)
+         it = h.begin(); it != h.end(); ++it)
     {
       printf("[%s] = [%s]\n", it->first.c_str(), it->second.c_str());
     }