changeset 340:f5d5814a41a0 am-2

rendering BitmapStack
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 20 Oct 2018 18:26:05 +0200
parents 5a7915b23138
children 7bebbfa56bde
files Applications/Samples/SingleFrameEditorApplication.h Framework/Toolbox/ImageGeometry.cpp Framework/Toolbox/ImageGeometry.h Framework/Toolbox/ShearWarpProjectiveTransform.cpp Framework/Toolbox/ViewportGeometry.cpp Framework/Toolbox/ViewportGeometry.h
diffstat 6 files changed, 170 insertions(+), 140 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Samples/SingleFrameEditorApplication.h	Fri Oct 19 14:44:12 2018 +0200
+++ b/Applications/Samples/SingleFrameEditorApplication.h	Sat Oct 20 18:26:05 2018 +0200
@@ -35,6 +35,9 @@
 #include <Plugins/Samples/Common/FullOrthancDataset.h>
 #include <Plugins/Samples/Common/DicomDatasetReader.h>
 
+
+#include <boost/math/constants/constants.hpp>
+
 namespace OrthancStone
 {
   class BitmapStack :
@@ -85,11 +88,11 @@
                        double y) const
       {
         Vector p;
-        LinearAlgebra::AssignVector(p, x, y, 0);
+        LinearAlgebra::AssignVector(p, x, y, 1);
 
         Vector q = LinearAlgebra::Product(transform_, p);
 
-        if (!LinearAlgebra::IsCloseToZero(q[2]))
+        if (!LinearAlgebra::IsNear(q[2], 1.0))
         {
           throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
         }
@@ -184,6 +187,25 @@
           transform_(1, 1) = pixelSpacing[1];
         }
 
+
+#if 0
+        double a = 10.0 / 180.0 * boost::math::constants::pi<double>();
+        Matrix m;
+        const double v[] = { cos(a), -sin(a), 0,
+                             sin(a), cos(a), 0,
+                             0, 0, 1 };
+        LinearAlgebra::FillMatrix(m, 3, 3, v);
+        transform_ = LinearAlgebra::Product(m, transform_);
+
+#else
+        static unsigned int c = 0;
+        if (c == 0)
+        {
+          transform_(0, 2) = 400;
+          c ++;
+        }
+#endif
+        
         OrthancPlugins::DicomDatasetReader reader(dataset);
 
         if (!reader.GetUnsignedIntegerValue(width_, ConvertTag(Orthanc::DICOM_TAG_COLUMNS)) ||
@@ -244,7 +266,8 @@
       {
         if (converted_.get() != NULL)
         {
-          ApplyProjectiveTransform(buffer, *converted_, transform_, ImageInterpolation_Nearest);  // TODO
+          Matrix m = LinearAlgebra::Product(view.GetMatrix(), transform_);
+          ApplyProjectiveTransform(buffer, *converted_, m, ImageInterpolation_Bilinear, false);
         }
       }
     }; 
@@ -402,7 +425,7 @@
     Extent2D GetSceneExtent() const
     {
       Extent2D extent;
-      
+
       for (Bitmaps::const_iterator it = bitmaps_.begin();
            it != bitmaps_.end(); ++it)
       {
@@ -410,10 +433,6 @@
         extent.Union(it->second->GetExtent());
       }
 
-      printf("(%.02f,%.02f) (%.02f,%.02f) \n",
-             extent.GetX1(), extent.GetY1(),
-             extent.GetX2(), extent.GetY2());
-      
       return extent;
     }
     
@@ -451,10 +470,41 @@
     virtual bool RenderScene(CairoContext& context,
                              const ViewportGeometry& view)
     {
-      Orthanc::Image buffer(Orthanc::PixelFormat_Float32, context.GetWidth(), context.GetHeight(), false);
-      stack_.Render(buffer, view);
+      // "Render()" has been replaced
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+
+  public:
+    BitmapStackWidget(MessageBroker& broker,
+                      BitmapStack& stack,
+                      const std::string& name) :
+      WorldSceneWidget(name),
+      IObservable(broker),
+      IObserver(broker),
+      stack_(stack)
+    {
+      stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::GeometryChangedMessage>(*this, &BitmapStackWidget::OnGeometryChanged));
+      stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::ContentChangedMessage>(*this, &BitmapStackWidget::OnContentChanged));
+    }
 
-      // As in GrayscaleFrameRenderer
+    void OnGeometryChanged(const BitmapStack::GeometryChangedMessage& message)
+    {
+      printf("Geometry has changed\n");
+      FitContent();
+    }
+
+    void OnContentChanged(const BitmapStack::ContentChangedMessage& message)
+    {
+      printf("Content has changed\n");
+      NotifyContentChanged();
+    }
+
+    virtual bool Render(Orthanc::ImageAccessor& target)
+    {
+      Orthanc::Image buffer(Orthanc::PixelFormat_Float32, target.GetWidth(), target.GetHeight(), false);
+      stack_.Render(buffer, GetView());
+
+      // As in GrayscaleFrameRenderer => TODO MERGE
 
       float windowCenter, windowWidth;
       stack_.GetWindowing(windowCenter, windowWidth);
@@ -462,13 +512,8 @@
       float x0 = windowCenter - windowWidth / 2.0f;
       float x1 = windowCenter + windowWidth / 2.0f;
 
-      CairoSurface cairo(context.GetWidth(), context.GetHeight());
-
-      Orthanc::ImageAccessor target;
-      cairo.GetAccessor(target);
-      
-      const unsigned int width = cairo.GetWidth();
-      const unsigned int height = cairo.GetHeight();
+      const unsigned int width = target.GetWidth();
+      const unsigned int height = target.GetHeight();
     
       for (unsigned int y = 0; y < height; y++)
       {
@@ -496,7 +541,7 @@
 
             // TODO MONOCHROME1
             /*if (invert_)
-            {
+              {
               v = 255 - v;
               }*/
           }
@@ -504,68 +549,21 @@
           q[3] = 255;
           q[2] = v;
           q[1] = v;
-          q[0] = 128;
+          q[0] = v;
         }
       }
 
-
-
-      cairo_t* cr = context.GetObject();
-
-      // Clear background
-      cairo_set_source_rgb(cr, 0, 0, 0);
-      cairo_paint(cr);
-
-#if 1
-      cairo_save(cr);
-      cairo_set_source_surface(cr, cairo.GetObject(), 0, 0);
-      cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);  //TODO
-      cairo_paint(cr);
-      cairo_restore(cr);
-#else      
-      Extent2D extent = stack_.GetSceneExtent();
-      
-      float color = 0.5;
-      cairo_set_source_rgb(cr, 0, 1.0f - color, color);
-      cairo_rectangle(cr, extent.GetX1(), extent.GetY1(), extent.GetX2(), extent.GetY2());
-      cairo_fill(cr);
-#endif
-
       return true;
     }
 
-  public:
-    BitmapStackWidget(MessageBroker& broker,
-                      BitmapStack& stack,
-                      const std::string& name) :
-      WorldSceneWidget(name),
-      IObservable(broker),
-      IObserver(broker),
-      stack_(stack)
-    {
-      stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::GeometryChangedMessage>(*this, &BitmapStackWidget::OnGeometryChanged));
-      stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::ContentChangedMessage>(*this, &BitmapStackWidget::OnContentChanged));
-    }
-
-    void OnGeometryChanged(const BitmapStack::GeometryChangedMessage& message)
-    {
-      printf("Geometry has changed\n");
-      FitContent();
-    }
-
-    void OnContentChanged(const BitmapStack::ContentChangedMessage& message)
-    {
-      printf("Content has changed\n");
-      NotifyContentChanged();
-    }
   };
 
   
   namespace Samples
   {
     class SingleFrameEditorApplication :
-        public SampleSingleCanvasApplicationBase,
-        public IObserver
+      public SampleSingleCanvasApplicationBase,
+      public IObserver
     {
       enum Tools
       {
@@ -603,14 +601,14 @@
                                                             IStatusBar* statusBar)
         {
           switch (application_.currentTool_) {
-          case Tools_Zoom:
-            printf("ZOOM\n");
+            case Tools_Zoom:
+              printf("ZOOM\n");
 
             case Tools_Crop:
-          case Tools_Windowing:
-          case Tools_Pan:
-            // TODO return the right mouse tracker
-            return NULL;
+            case Tools_Windowing:
+            case Tools_Pan:
+              // TODO return the right mouse tracker
+              return NULL;
           }
 
           return NULL;
@@ -646,35 +644,35 @@
         {
           switch (keyChar)
           {
-          case 's':
-            widget.FitContent();
-            break;
-          case 'p':
-            application_.currentTool_ = Tools_Pan;
-            break;
-          case 'z':
-            application_.currentTool_ = Tools_Zoom;
-            break;
-          case 'c':
-            application_.currentTool_ = Tools_Crop;
-            break;
-          case 'w':
-            application_.currentTool_ = Tools_Windowing;
-            break;
-          case 'i':
-            application_.Invert();
-            break;
-          case 'r':
-            if (modifiers == KeyboardModifiers_None)
-              application_.Rotate(90);
-            else
-              application_.Rotate(-90);
-            break;
-          case 'e':
-            application_.Export();
-            break;
-          default:
-            break;
+            case 's':
+              widget.FitContent();
+              break;
+            case 'p':
+              application_.currentTool_ = Tools_Pan;
+              break;
+            case 'z':
+              application_.currentTool_ = Tools_Zoom;
+              break;
+            case 'c':
+              application_.currentTool_ = Tools_Crop;
+              break;
+            case 'w':
+              application_.currentTool_ = Tools_Windowing;
+              break;
+            case 'i':
+              application_.Invert();
+              break;
+            case 'r':
+              if (modifiers == KeyboardModifiers_None)
+                application_.Rotate(90);
+              else
+                application_.Rotate(-90);
+              break;
+            case 'e':
+              application_.Export();
+              break;
+            default:
+              break;
           }
         }
       };
@@ -699,11 +697,11 @@
       {
         boost::program_options::options_description generic("Sample options");
         generic.add_options()
-            ("instance", boost::program_options::value<std::string>(),
-             "Orthanc ID of the instance")
-            ("frame", boost::program_options::value<unsigned int>()->default_value(0),
-             "Number of the frame, for multi-frame DICOM instances")
-            ;
+          ("instance", boost::program_options::value<std::string>(),
+           "Orthanc ID of the instance")
+          ("frame", boost::program_options::value<unsigned int>()->default_value(0),
+           "Number of the frame, for multi-frame DICOM instances")
+          ;
 
         options.add(generic);
       }
@@ -731,7 +729,7 @@
 
         stack_.reset(new BitmapStack(IObserver::broker_, *orthancApiClient_));
         stack_->LoadFrame(instance, frame, false);
-        //stack_->LoadFrame(instance, frame, false);
+        stack_->LoadFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", frame, false);
         
         mainWidget_ = new BitmapStackWidget(IObserver::broker_, *stack_, "main-widget");
         mainWidget_->SetTransmitMouseOver(true);
--- a/Framework/Toolbox/ImageGeometry.cpp	Fri Oct 19 14:44:12 2018 +0200
+++ b/Framework/Toolbox/ImageGeometry.cpp	Sat Oct 20 18:26:05 2018 +0200
@@ -174,7 +174,8 @@
             ImageInterpolation Interpolation>
   static void ApplyAffineInternal(Orthanc::ImageAccessor& target,
                                   const Orthanc::ImageAccessor& source,
-                                  const Matrix& a)
+                                  const Matrix& a,
+                                  bool clear)
   {
     assert(target.GetFormat() == Format &&
            source.GetFormat() == Format);
@@ -182,13 +183,16 @@
     typedef SubpixelReader<Format, Interpolation>  Reader;
     typedef typename Reader::PixelType             PixelType;
 
-    if (Format == Orthanc::PixelFormat_RGB24)
+    if (clear)
     {
-      Orthanc::ImageProcessing::Set(target, 0, 0, 0, 255);
-    }
-    else
-    {
-      Orthanc::ImageProcessing::Set(target, 0);
+      if (Format == Orthanc::PixelFormat_RGB24)
+      {
+        Orthanc::ImageProcessing::Set(target, 0, 0, 0, 255);
+      }
+      else
+      {
+        Orthanc::ImageProcessing::Set(target, 0);
+      }
     }
 
     Matrix inva;
@@ -260,7 +264,8 @@
                             double a21,
                             double a22,
                             double b2,
-                            ImageInterpolation interpolation)
+                            ImageInterpolation interpolation,
+                            bool clear)
   {
     if (source.GetFormat() != target.GetFormat())
     {
@@ -292,12 +297,12 @@
         {
           case ImageInterpolation_Nearest:
             ApplyAffineInternal<Orthanc::PixelFormat_Grayscale8, 
-                                ImageInterpolation_Nearest>(target, source, a);
+                                ImageInterpolation_Nearest>(target, source, a, clear);
             break;
 
           case ImageInterpolation_Bilinear:
             ApplyAffineInternal<Orthanc::PixelFormat_Grayscale8, 
-                                ImageInterpolation_Bilinear>(target, source, a);
+                                ImageInterpolation_Bilinear>(target, source, a, clear);
             break;
 
           default:
@@ -310,12 +315,12 @@
         {
           case ImageInterpolation_Nearest:
             ApplyAffineInternal<Orthanc::PixelFormat_Grayscale16, 
-                                ImageInterpolation_Nearest>(target, source, a);
+                                ImageInterpolation_Nearest>(target, source, a, clear);
             break;
 
           case ImageInterpolation_Bilinear:
             ApplyAffineInternal<Orthanc::PixelFormat_Grayscale16, 
-                                ImageInterpolation_Bilinear>(target, source, a);
+                                ImageInterpolation_Bilinear>(target, source, a, clear);
             break;
 
           default:
@@ -328,12 +333,12 @@
         {
           case ImageInterpolation_Nearest:
             ApplyAffineInternal<Orthanc::PixelFormat_SignedGrayscale16, 
-                                ImageInterpolation_Nearest>(target, source, a);
+                                ImageInterpolation_Nearest>(target, source, a, clear);
             break;
 
           case ImageInterpolation_Bilinear:
             ApplyAffineInternal<Orthanc::PixelFormat_SignedGrayscale16, 
-                                ImageInterpolation_Bilinear>(target, source, a);
+                                ImageInterpolation_Bilinear>(target, source, a, clear);
             break;
 
           default:
@@ -346,12 +351,12 @@
         {
           case ImageInterpolation_Nearest:
             ApplyAffineInternal<Orthanc::PixelFormat_Float32, 
-                                ImageInterpolation_Nearest>(target, source, a);
+                                ImageInterpolation_Nearest>(target, source, a, clear);
             break;
 
           case ImageInterpolation_Bilinear:
             ApplyAffineInternal<Orthanc::PixelFormat_Float32, 
-                                ImageInterpolation_Bilinear>(target, source, a);
+                                ImageInterpolation_Bilinear>(target, source, a, clear);
             break;
 
           default:
@@ -364,7 +369,7 @@
         {
           case ImageInterpolation_Nearest:
             ApplyAffineInternal<Orthanc::PixelFormat_RGB24, 
-                                ImageInterpolation_Nearest>(target, source, a);
+                                ImageInterpolation_Nearest>(target, source, a, clear);
             break;
 
           default:
@@ -447,7 +452,8 @@
   void ApplyProjectiveTransform(Orthanc::ImageAccessor& target,
                                 const Orthanc::ImageAccessor& source,
                                 const Matrix& a,
-                                ImageInterpolation interpolation)
+                                ImageInterpolation interpolation,
+                                bool clear)
   {
     if (source.GetFormat() != target.GetFormat())
     {
@@ -481,18 +487,21 @@
         ApplyAffineTransform(target, source, 
                              a(0, 0) / w, a(0, 1) / w, a(0, 2) / w,
                              a(1, 0) / w, a(1, 1) / w, a(1, 2) / w,
-                             interpolation);
+                             interpolation, clear);
         return;
       }
     }
 
-    if (target.GetFormat() == Orthanc::PixelFormat_RGB24)
+    if (clear)
     {
-      Orthanc::ImageProcessing::Set(target, 0, 0, 0, 255);
-    }
-    else
-    {
-      Orthanc::ImageProcessing::Set(target, 0);
+      if (target.GetFormat() == Orthanc::PixelFormat_RGB24)
+      {
+        Orthanc::ImageProcessing::Set(target, 0, 0, 0, 255);
+      }
+      else
+      {
+        Orthanc::ImageProcessing::Set(target, 0);
+      }
     }
 
     Matrix inva;
--- a/Framework/Toolbox/ImageGeometry.h	Fri Oct 19 14:44:12 2018 +0200
+++ b/Framework/Toolbox/ImageGeometry.h	Sat Oct 20 18:26:05 2018 +0200
@@ -50,10 +50,12 @@
                             double a21,
                             double a22,
                             double b2,
-                            ImageInterpolation interpolation);
+                            ImageInterpolation interpolation,
+                            bool clear);
 
   void ApplyProjectiveTransform(Orthanc::ImageAccessor& target,
                                 const Orthanc::ImageAccessor& source,
                                 const Matrix& a,
-                                ImageInterpolation interpolation);
+                                ImageInterpolation interpolation,
+                                bool clear);
 }
--- a/Framework/Toolbox/ShearWarpProjectiveTransform.cpp	Fri Oct 19 14:44:12 2018 +0200
+++ b/Framework/Toolbox/ShearWarpProjectiveTransform.cpp	Sat Oct 20 18:26:05 2018 +0200
@@ -476,7 +476,7 @@
         ApplyAffineTransform(*intermediate, reader.GetAccessor(),
                              a11, 0,   b1,
                              0,   a22, b2,
-                             shearInterpolation);
+                             shearInterpolation, true);
       }
       
 
@@ -582,7 +582,7 @@
     }
 
     // (5.b) Apply the projective transform to the image
-    ApplyProjectiveTransform(target, *intermediate, warp, warpInterpolation);
+    ApplyProjectiveTransform(target, *intermediate, warp, warpInterpolation, true);
   }
 
 
--- a/Framework/Toolbox/ViewportGeometry.cpp	Fri Oct 19 14:44:12 2018 +0200
+++ b/Framework/Toolbox/ViewportGeometry.cpp	Sat Oct 20 18:26:05 2018 +0200
@@ -179,4 +179,22 @@
     zoom_ = zoom;
     ComputeTransform();
   }
+
+
+  Matrix ViewportGeometry::GetMatrix() const
+  {
+    Matrix m(3, 3);
+
+    m(0, 0) = transform_.xx;
+    m(0, 1) = transform_.xy;
+    m(0, 2) = transform_.x0;
+    m(1, 0) = transform_.yx;
+    m(1, 1) = transform_.yy;
+    m(1, 2) = transform_.y0;
+    m(2, 0) = 0;
+    m(2, 1) = 0;
+    m(2, 2) = 1;
+    
+    return m;
+  }
 }
--- a/Framework/Toolbox/ViewportGeometry.h	Fri Oct 19 14:44:12 2018 +0200
+++ b/Framework/Toolbox/ViewportGeometry.h	Sat Oct 20 18:26:05 2018 +0200
@@ -22,7 +22,8 @@
 #pragma once
 
 #include "../Viewport/CairoContext.h"
-#include "../Toolbox/Extent2D.h"
+#include "Extent2D.h"
+#include "LinearAlgebra.h"
 
 namespace OrthancStone
 {
@@ -99,5 +100,7 @@
                 double y);
 
     void SetZoom(double zoom);
+
+    Matrix GetMatrix() const;
   };
 }