changeset 120:063f7f3d9f14 wasm

fix 3d locations of the doses
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 04 Oct 2017 15:51:34 +0200
parents ba83e38cf3ff
children e66b2c757790
files Applications/Samples/SingleVolumeApplication.h Framework/Toolbox/DicomFrameConverter.cpp Framework/Toolbox/OrthancSlicesLoader.cpp Framework/Toolbox/OrthancSlicesLoader.h Framework/Toolbox/Slice.cpp Framework/dev.h
diffstat 6 files changed, 127 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Samples/SingleVolumeApplication.h	Mon Oct 02 22:01:41 2017 +0200
+++ b/Applications/Samples/SingleVolumeApplication.h	Wed Oct 04 15:51:34 2017 +0200
@@ -54,10 +54,22 @@
 
           if (image.FitWindowingToRange(s, slice.GetConverter()))
           {
-            //printf("ICI: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);
+            //printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);
             widget_.SetLayerStyle(layer_, s);
           }
         }
+
+        virtual void MouseOver(CairoContext& context,
+                               WorldSceneWidget& widget,
+                               const ViewportGeometry& view,
+                               double x,
+                               double y,
+                               IStatusBar* statusBar)
+        {
+          const LayerWidget& w = dynamic_cast<const LayerWidget&>(widget);
+          Vector p = w.GetSlice().MapSliceToWorldCoordinates(x, y);
+          printf("%f %f %f\n", p[0], p[1], p[2]);
+        }
       
       public:
         Interactor(OrthancVolumeImage& volume,
@@ -185,19 +197,21 @@
 #else
         std::auto_ptr<OrthancVolumeImage> ct(new OrthancVolumeImage(context.GetWebService(), false));
         //ct->ScheduleLoadSeries("dd069910-4f090474-7d2bba07-e5c10783-f9e4fb1d");
-        //ct->ScheduleLoadSeries("3025d8df-a82f3b00-83942fa3-ee6a6be3-a8bf32e8");
-        ct->ScheduleLoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa");
-
+        ct->ScheduleLoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa");  // IBA
+        //ct->ScheduleLoadSeries("03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0");  // 0522c0001 TCIA
+  
         std::auto_ptr<OrthancVolumeImage> pet(new OrthancVolumeImage(context.GetWebService(), true));
         //pet->ScheduleLoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e");
-        //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb");
-        //pet->ScheduleLoadInstance("337876a1-a68a9718-f15abccd-38faafa1-b99b496a");
-        pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb");
+        pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 1
+        //pet->ScheduleLoadInstance("337876a1-a68a9718-f15abccd-38faafa1-b99b496a"); // IBA 2
+        //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb");  // IBA 3
+        //pet->ScheduleLoadInstance("269f26f4-0c83eeeb-2e67abbd-5467a40f-f1bec90c");  // 0522c0001 TCIA
 
         widget->AddLayer(new VolumeImageSource(*ct));
         widget->AddLayer(new VolumeImageSource(*pet));
         
-        context.AddInteractor(new Interactor(*pet, *widget, projection, 1));
+        //context.AddInteractor(new Interactor(*pet, *widget, projection, 1));
+        context.AddInteractor(new VolumeImageInteractor(*ct, *widget, projection));
         context.AddVolume(ct.release());
         context.AddVolume(pet.release());
 
@@ -217,6 +231,9 @@
           s.applyLut_ = true;
           s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
           s.interpolation_ = ImageInterpolation_Linear;
+          s.windowing_ = ImageWindowing_Custom;
+          s.customWindowCenter_ = 0;
+          s.customWindowWidth_ = 128;
           widget->SetLayerStyle(1, s);
         }
 #endif
--- a/Framework/Toolbox/DicomFrameConverter.cpp	Mon Oct 02 22:01:41 2017 +0200
+++ b/Framework/Toolbox/DicomFrameConverter.cpp	Wed Oct 04 15:51:34 2017 +0200
@@ -81,6 +81,26 @@
       isRTDose = true;
       rescaleIntercept_ = 0;
       rescaleSlope_ = doseGridScaling;
+
+      if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_BITS_STORED))
+      {
+        // Type 1 tag, must be present
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      }
+
+      switch (tmp)
+      {
+        case 16:
+          expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
+          break;
+
+        case 32:
+          expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32;
+          break;
+
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+      }
     }
 
     std::string photometric;
@@ -100,21 +120,20 @@
     // TODO Add more checks, e.g. on the number of bytes per value
     // (cf. DicomImageInformation.h in Orthanc)
 
-    if (isRTDose)
-    {
-      expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32;
-    }
-    else if (isColor_)
+    if (!isRTDose)
     {
-      expectedPixelFormat_ = Orthanc::PixelFormat_RGB24;
-    }
-    else if (isSigned_)
-    {
-      expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16;
-    }
-    else
-    {
-      expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
+      if (isColor_)
+      {
+        expectedPixelFormat_ = Orthanc::PixelFormat_RGB24;
+      }
+      else if (isSigned_)
+      {
+        expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16;
+      }
+      else
+      {
+        expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
+      }
     }
   }
 
--- a/Framework/Toolbox/OrthancSlicesLoader.cpp	Mon Oct 02 22:01:41 2017 +0200
+++ b/Framework/Toolbox/OrthancSlicesLoader.cpp	Wed Oct 04 15:51:34 2017 +0200
@@ -277,6 +277,37 @@
       (*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality());
   }
 
+
+  void OrthancSlicesLoader::SortAndFinalizeSlices()
+  {
+    bool ok = false;
+    
+    if (slices_.GetSliceCount() > 0)
+    {
+      Vector normal;
+      if (slices_.SelectNormal(normal))
+      {
+        slices_.FilterNormal(normal);
+        slices_.SetNormal(normal);
+        slices_.Sort();
+        ok = true;
+      }
+    }
+
+    state_ = State_GeometryReady;
+
+    if (ok)
+    {
+      LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)";
+      userCallback_.NotifyGeometryReady(*this);
+    }
+    else
+    {
+      LOG(ERROR) << "This series is empty";
+      userCallback_.NotifyGeometryError(*this);
+    }
+  }
+
   
   void OrthancSlicesLoader::ParseSeriesGeometry(const void* answer,
                                                 size_t size)
@@ -320,32 +351,7 @@
       }
     }
 
-    bool ok = false;
-      
-    if (slices_.GetSliceCount() > 0)
-    {
-      Vector normal;
-      if (slices_.SelectNormal(normal))
-      {
-        slices_.FilterNormal(normal);
-        slices_.SetNormal(normal);
-        slices_.Sort();
-        ok = true;
-      }
-    }
-
-    state_ = State_GeometryReady;
-
-    if (ok)
-    {
-      LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)";
-      userCallback_.NotifyGeometryReady(*this);
-    }
-    else
-    {
-      LOG(ERROR) << "This series is empty";
-      userCallback_.NotifyGeometryError(*this);
-    }
+    SortAndFinalizeSlices();
   }
 
 
@@ -374,8 +380,6 @@
     
     LOG(INFO) << "Instance " << instanceId << " contains " << frames << " frame(s)";
 
-    state_ = State_GeometryReady;
-
     for (unsigned int frame = 0; frame < frames; frame++)
     {
       std::auto_ptr<Slice> slice(new Slice);
@@ -391,7 +395,7 @@
       }
     }
 
-    userCallback_.NotifyGeometryReady(*this);
+    SortAndFinalizeSlices();
   }
 
 
@@ -671,6 +675,7 @@
         (new StringImage(Orthanc::PixelFormat_Grayscale32, info.GetWidth(),
                          info.GetHeight(), raw));
 
+      // TODO - Only for big endian
       for (unsigned int y = 0; y < image->GetHeight(); y++)
       {
         uint32_t *p = reinterpret_cast<uint32_t*>(image->GetRow(y));
@@ -682,6 +687,22 @@
 
       NotifySliceImageSuccess(operation, image);
     }
+    else if (info.GetBitsAllocated() == 16 &&
+             info.GetBitsStored() == 16 &&
+             info.GetHighBit() == 15 &&
+             info.GetChannelCount() == 1 &&
+             !info.IsSigned() &&
+             info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 &&
+             raw.size() == info.GetWidth() * info.GetHeight() * 2)
+    {
+      std::auto_ptr<Orthanc::ImageAccessor> image
+        (new StringImage(Orthanc::PixelFormat_Grayscale16, info.GetWidth(),
+                         info.GetHeight(), raw));
+
+      // TODO - Big endian ?
+
+      NotifySliceImageSuccess(operation, image);
+    }
     else
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
--- a/Framework/Toolbox/OrthancSlicesLoader.h	Mon Oct 02 22:01:41 2017 +0200
+++ b/Framework/Toolbox/OrthancSlicesLoader.h	Wed Oct 04 15:51:34 2017 +0200
@@ -118,6 +118,8 @@
     void ScheduleSliceImageJpeg(const Slice& slice,
                                 size_t index,
                                 SliceImageQuality quality);
+
+    void SortAndFinalizeSlices();
     
   public:
     OrthancSlicesLoader(ICallback& callback,
--- a/Framework/Toolbox/Slice.cpp	Mon Oct 02 22:01:41 2017 +0200
+++ b/Framework/Toolbox/Slice.cpp	Wed Oct 04 15:51:34 2017 +0200
@@ -69,7 +69,7 @@
     std::vector<std::string> offsets;
     Orthanc::Toolbox::TokenizeString(offsets, offsetTag, '\\');
 
-    if (frameCount_ == 0 ||
+    if (frameCount_ <= 1 ||
         offsets.size() != frameCount_ ||
         frame >= frameCount_)
     {
@@ -77,9 +77,10 @@
       return false;
     }
 
-    double offset0, z;
+    double offset0, offset1, z;
 
     if (!ParseDouble(offset0, offsets[0]) ||
+        !ParseDouble(offset1, offsets[1]) ||
         !ParseDouble(z, offsets[frame]))
     {
       LOG(ERROR) << "Invalid syntax";
@@ -93,8 +94,18 @@
     }
 
     geometry_ = CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(),
+                                   //+ 650 * geometry_.GetAxisX(),
                                    geometry_.GetAxisX(),
                                    geometry_.GetAxisY());
+
+    thickness_ = offset1 - offset0;
+    if (thickness_ < 0)
+    {
+      thickness_ = -thickness_;
+    }
+
+    printf("%d: %f %f %f\n", frame_, geometry_.GetOrigin()[0], geometry_.GetOrigin()[1], geometry_.GetOrigin()[2]);
+    //printf("%f %f %f\n", pixelSpacingX_, pixelSpacingY_, thickness_);
     
     return true;
   }
--- a/Framework/dev.h	Mon Oct 02 22:01:41 2017 +0200
+++ b/Framework/dev.h	Wed Oct 04 15:51:34 2017 +0200
@@ -133,7 +133,7 @@
         // z-dimension for voxels
         spacingZ = 1;
       }
-      
+
       for (size_t i = 1; i < loader.GetSliceCount(); i++)
       {
         if (!GeometryToolbox::IsNear(spacingZ, GetDistance(loader.GetSlice(i - 1), loader.GetSlice(i)),
@@ -156,7 +156,7 @@
       image_->SetVoxelDimensions(loader.GetSlice(0).GetPixelSpacingX(), 
                                  loader.GetSlice(0).GetPixelSpacingY(), spacingZ);
       image_->Clear();
-
+      
       downloadStack_.reset(new DownloadStack(loader.GetSliceCount()));
 
       for (unsigned int i = 0; i < 4; i++)  // Limit to 4 simultaneous downloads
@@ -391,8 +391,6 @@
         default:
           throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
       }
-
-      //sliceThickness_ = 3.0f;  // TODO XXXXX
     }
 
     size_t GetSliceCount() const
@@ -645,10 +643,10 @@
       if (slices_.get() == NULL)
       {
         const OrthancVolumeImage& image = dynamic_cast<const OrthancVolumeImage&>(volume);
-          
+
         slices_.reset(new VolumeImageGeometry(image, projection_));
         SetSlice(slices_->GetSliceCount() / 2);
-          
+
         widget_.SetDefaultView();
       }
     }