changeset 335:62dd571a40af

created OnTheFlyPyramid class
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 04 Dec 2024 22:37:58 +0100
parents f011fc199b6a
children dfd9ecf38091
files .clang-format Applications/CMakeLists.txt Framework/Inputs/OnTheFlyPyramid.cpp Framework/Inputs/OnTheFlyPyramid.h ViewerPlugin/CMakeLists.txt
diffstat 5 files changed, 276 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.clang-format	Wed Dec 04 22:37:58 2024 +0100
@@ -0,0 +1,57 @@
+---
+Language: Cpp
+BasedOnStyle: LLVM
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignOperands: true
+AlignTrailingComments: false
+AlwaysBreakTemplateDeclarations: Yes
+BraceWrapping: 
+  AfterCaseLabel: true
+  AfterClass: true
+  AfterControlStatement: true
+  AfterEnum: true
+  AfterFunction: true
+  AfterNamespace: true
+  AfterStruct: true
+  AfterUnion: true
+  AfterExternBlock: true
+  BeforeCatch: true
+  BeforeElse: true
+  BeforeLambdaBody: true
+  BeforeWhile: true
+  IndentBraces: false
+  SplitEmptyFunction: true
+  SplitEmptyRecord: true
+  SplitEmptyNamespace: true
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializers: AfterColon
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 200
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ContinuationIndentWidth: 2
+IncludeCategories: 
+  - Regex: '^<.*'
+    Priority: 1
+  - Regex: '^".*'
+    Priority: 2
+  - Regex: '.*'
+    Priority: 3
+IncludeIsMainRegex: '([-_](test|unittest))?$'
+IndentCaseLabels: true
+InsertNewlineAtEOF: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 2
+NamespaceIndentation: All
+SpaceAfterCStyleCast: true
+SpaceAfterTemplateKeyword: false
+SpaceBeforeRangeBasedForLoopColon: false
+SpaceInEmptyParentheses: false
+SpacesInAngles: false
+SpacesInConditionalStatement: false
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+TabWidth: 2
+...
--- a/Applications/CMakeLists.txt	Fri Oct 18 15:44:18 2024 +0200
+++ b/Applications/CMakeLists.txt	Wed Dec 04 22:37:58 2024 +0100
@@ -119,6 +119,7 @@
   ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramidInstance.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramidLevel.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/HierarchicalTiff.cpp
+  ${ORTHANC_WSI_DIR}/Framework/Inputs/OnTheFlyPyramid.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/OpenSlideLibrary.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/OpenSlidePyramid.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/PlainTiff.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Inputs/OnTheFlyPyramid.cpp	Wed Dec 04 22:37:58 2024 +0100
@@ -0,0 +1,122 @@
+/**
+* Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "../PrecompiledHeadersWSI.h"
+#include "OnTheFlyPyramid.h"
+
+#include <OrthancException.h>
+
+#include <cassert>
+#include <Images/Image.h>
+#include <Images/ImageProcessing.h>
+
+#include "../../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h"
+
+namespace OrthancWSI
+{
+  void OnTheFlyPyramid::ReadRegion(Orthanc::ImageAccessor &target,
+                                   bool &isEmpty,
+                                   unsigned level,
+                                   unsigned x,
+                                   unsigned y)
+  {
+    isEmpty = false;
+    GetLevel(level).GetRegion(target, x, y, tileWidth_, tileHeight_);
+  }
+
+
+  OnTheFlyPyramid::OnTheFlyPyramid(Orthanc::ImageAccessor *baseLevel,
+                                   unsigned int tileWidth,
+                                   unsigned int tileHeight,
+                                   bool smooth) :
+    tileWidth_(tileWidth),
+    tileHeight_(tileHeight)
+  {
+    if (baseLevel == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+
+    std::unique_ptr<Orthanc::ImageAccessor> protection(baseLevel);
+
+    if (protection->GetFormat() == Orthanc::PixelFormat_RGB24)
+    {
+      baseLevel_.reset(protection.release());
+    }
+    else
+    {
+      baseLevel_.reset(new Orthanc::Image(Orthanc::PixelFormat_RGB24, protection->GetWidth(), protection->GetHeight(), false));
+      Orthanc::ImageProcessing::Convert(*baseLevel_, *protection);
+    }
+
+    Orthanc::ImageAccessor* current = baseLevel_.get();
+    while (current->GetWidth() > tileWidth_ ||
+           current->GetHeight() > tileHeight_)
+    {
+      std::unique_ptr<Orthanc::ImageAccessor> next;
+
+      if (smooth)
+      {
+        std::unique_ptr<Orthanc::ImageAccessor> smoothed(Orthanc::Image::Clone(*current));
+        Orthanc::ImageProcessing::SmoothGaussian5x5(*smoothed, false);
+        next.reset(Orthanc::ImageProcessing::Halve(*smoothed, false));
+      }
+      else
+      {
+        next.reset(Orthanc::ImageProcessing::Halve(*current, false));
+      }
+
+      higherLevels_.push_back(next.release());
+      current = higherLevels_.back();
+    }
+  }
+
+
+  OnTheFlyPyramid::~OnTheFlyPyramid()
+  {
+    for (size_t i = 0; i < higherLevels_.size(); i++)
+    {
+      assert(higherLevels_[i] != NULL);
+      delete higherLevels_[i];
+    }
+  }
+
+
+  const Orthanc::ImageAccessor & OnTheFlyPyramid::GetLevel(unsigned int level) const
+  {
+    if (level >= GetLevelCount())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    else if (level == 0)
+    {
+      assert(baseLevel_.get() != NULL);
+      return *baseLevel_;
+    }
+    else
+    {
+      assert(higherLevels_[level - 1] != NULL);
+      return *higherLevels_[level - 1];
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Inputs/OnTheFlyPyramid.h	Wed Dec 04 22:37:58 2024 +0100
@@ -0,0 +1,94 @@
+/**
+* Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "DecodedTiledPyramid.h"
+
+#include <Compatibility.h>
+
+#include <vector>
+
+namespace OrthancWSI
+{
+ class OnTheFlyPyramid : public DecodedTiledPyramid
+ {
+ private:
+   std::unique_ptr<Orthanc::ImageAccessor>  baseLevel_;
+   std::vector<Orthanc::ImageAccessor*>     higherLevels_;
+   unsigned int                             tileWidth_;
+   unsigned int                             tileHeight_;
+
+ protected:
+   void ReadRegion(Orthanc::ImageAccessor &target,
+                   bool &isEmpty,
+                   unsigned level,
+                   unsigned x,
+                   unsigned y) ORTHANC_OVERRIDE;
+
+ public:
+   OnTheFlyPyramid(Orthanc::ImageAccessor* baseLevel /* takes ownership */,
+                   unsigned int tileWidth,
+                   unsigned int tileHeight,
+                   bool smooth);
+
+   virtual ~OnTheFlyPyramid();
+
+   const Orthanc::ImageAccessor& GetLevel(unsigned int level) const;
+
+   unsigned GetLevelCount() const ORTHANC_OVERRIDE
+   {
+     return higherLevels_.size() + 1 /* base level */;
+   }
+
+   unsigned GetLevelWidth(unsigned int level) const ORTHANC_OVERRIDE
+   {
+     return GetLevel(level).GetWidth();
+   }
+
+   unsigned GetLevelHeight(unsigned int level) const ORTHANC_OVERRIDE
+   {
+     return GetLevel(level).GetHeight();
+   }
+
+   unsigned GetTileWidth(unsigned int level) const ORTHANC_OVERRIDE
+   {
+     return tileWidth_;
+   }
+
+   unsigned GetTileHeight(unsigned level) const ORTHANC_OVERRIDE
+   {
+     return tileHeight_;
+   }
+
+   Orthanc::PixelFormat GetPixelFormat() const ORTHANC_OVERRIDE
+   {
+     return baseLevel_->GetFormat();
+   }
+
+   Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const ORTHANC_OVERRIDE
+   {
+     return Orthanc::PhotometricInterpretation_RGB;
+   }
+ };
+}
--- a/ViewerPlugin/CMakeLists.txt	Fri Oct 18 15:44:18 2024 +0200
+++ b/ViewerPlugin/CMakeLists.txt	Wed Dec 04 22:37:58 2024 +0100
@@ -195,9 +195,11 @@
   ${ORTHANC_WSI_DIR}/Framework/DicomToolbox.cpp
   ${ORTHANC_WSI_DIR}/Framework/Enumerations.cpp
   ${ORTHANC_WSI_DIR}/Framework/ImageToolbox.cpp
+  ${ORTHANC_WSI_DIR}/Framework/Inputs/DecodedTiledPyramid.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramid.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramidInstance.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramidLevel.cpp
+  ${ORTHANC_WSI_DIR}/Framework/Inputs/OnTheFlyPyramid.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/PyramidWithRawTiles.cpp
   ${ORTHANC_WSI_DIR}/Framework/Jpeg2000Reader.cpp
   ${ORTHANC_WSI_DIR}/Framework/Jpeg2000Writer.cpp