diff Framework/Algorithms/ReconstructPyramidCommand.cpp @ 0:4a7a53257c7d

initial commit
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 22 Oct 2016 21:48:33 +0200
parents
children 7a88c614be04
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Algorithms/ReconstructPyramidCommand.cpp	Sat Oct 22 21:48:33 2016 +0200
@@ -0,0 +1,184 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 "ReconstructPyramidCommand.h"
+
+#include "../ImageToolbox.h"
+#include "../Orthanc/Core/Logging.h"
+#include "../Orthanc/Core/OrthancException.h"
+#include "../Orthanc/Core/Images/Image.h"
+
+#include <cassert>
+
+namespace OrthancWSI
+{
+  Orthanc::ImageAccessor* ReconstructPyramidCommand::Explore(unsigned int level,
+                                                             unsigned int offsetX,
+                                                             unsigned int offsetY)
+  {
+    unsigned int zoom = 1 << level;
+    assert(x_ % zoom == 0 && y_ % zoom == 0);
+    unsigned int x = x_ / zoom + offsetX;
+    unsigned int y = y_ / zoom + offsetY;
+
+    if (x >= target_.GetCountTilesX(level + shiftTargetLevel_) ||
+        y >= target_.GetCountTilesY(level + shiftTargetLevel_))
+    {
+      return NULL;
+    }
+
+    std::auto_ptr<Orthanc::ImageAccessor> result;
+
+    if (level == 0)
+    {
+      result.reset(new Orthanc::ImageAccessor(source_.GetDecodedTile(x, y)));
+
+      const std::string* rawTile = source_.GetRawTile(x, y);
+
+      if (rawTile != NULL)
+      {
+        // Simple transcoding
+        target_.WriteRawTile(*rawTile, source_.GetImageCompression(), level + shiftTargetLevel_, x, y);
+      }
+      else
+      {
+        // Re-encoding the file
+        target_.EncodeTile(*result, level + shiftTargetLevel_, x, y);
+      }
+    }
+    else
+    {
+      std::auto_ptr<Orthanc::ImageAccessor> mosaic(ImageToolbox::Allocate(source_.GetPixelFormat(), 
+                                                                          2 * target_.GetTileWidth(), 
+                                                                          2 * target_.GetTileHeight()));
+      ImageToolbox::Set(*mosaic, 
+                        source_.GetParameters().GetBackgroundColorRed(),
+                        source_.GetParameters().GetBackgroundColorGreen(),
+                        source_.GetParameters().GetBackgroundColorBlue());
+
+      {
+        std::auto_ptr<Orthanc::ImageAccessor> subTile(Explore(level - 1, 2 * offsetX, 2 * offsetY));
+        if (subTile.get() != NULL)
+        {
+          ImageToolbox::Embed(*mosaic, *subTile, 0, 0);
+        }
+      }
+
+      {
+        std::auto_ptr<Orthanc::ImageAccessor> subTile(Explore(level - 1, 2 * offsetX + 1, 2 * offsetY));
+        if (subTile.get() != NULL)
+        {
+          ImageToolbox::Embed(*mosaic, *subTile, target_.GetTileWidth(), 0);
+        }
+      }
+
+      {
+        std::auto_ptr<Orthanc::ImageAccessor> subTile(Explore(level - 1, 2 * offsetX, 2 * offsetY + 1));
+        if (subTile.get() != NULL)
+        {
+          ImageToolbox::Embed(*mosaic, *subTile, 0, target_.GetTileHeight());
+        }
+      }
+
+      {
+        std::auto_ptr<Orthanc::ImageAccessor> subTile(Explore(level - 1, 2 * offsetX + 1, 2 * offsetY + 1));
+        if (subTile.get() != NULL)
+        {
+          ImageToolbox::Embed(*mosaic, *subTile, target_.GetTileWidth(), target_.GetTileHeight());
+        }
+      }
+
+      result.reset(ImageToolbox::Halve(*mosaic, source_.GetParameters().IsSmoothEnabled()));
+
+      target_.EncodeTile(*result, level + shiftTargetLevel_, x, y);
+    }
+
+    return result.release();
+  }
+
+  
+  ReconstructPyramidCommand::ReconstructPyramidCommand(IPyramidWriter& target,
+                                                       ITiledPyramid& source,
+                                                       unsigned int upToLevel,
+                                                       unsigned int x,
+                                                       unsigned int y,
+                                                       const DicomizerParameters& parameters) :
+    target_(target),
+    source_(source, 0, target.GetTileWidth(), target.GetTileHeight(), parameters),
+    upToLevel_(upToLevel),
+    x_(x),
+    y_(y),
+    shiftTargetLevel_(0)
+  {
+    unsigned int zoom = 1 << upToLevel;
+    if (x % zoom != 0 ||
+        y % zoom != 0)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+
+    if (target.GetPixelFormat() != source.GetPixelFormat())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+    }
+  }
+
+
+  bool ReconstructPyramidCommand::Execute()
+  {
+    std::auto_ptr<Orthanc::ImageAccessor> root(Explore(upToLevel_, 0, 0));
+    return true;
+  }
+
+
+  void ReconstructPyramidCommand::PrepareBagOfTasks(Orthanc::BagOfTasks& tasks,
+                                                    IPyramidWriter& target,
+                                                    ITiledPyramid& source,
+                                                    unsigned int countLevels,
+                                                    unsigned int shiftTargetLevel,    
+                                                    const DicomizerParameters& parameters)
+  {
+    if (countLevels == 0)
+    {
+      return;
+    }
+
+    if (shiftTargetLevel + countLevels > target.GetLevelCount())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    const unsigned int targetCountTilesX = target.GetCountTilesX(shiftTargetLevel);
+    const unsigned int targetCountTilesY = target.GetCountTilesY(shiftTargetLevel);
+    const unsigned int step = 1 << (countLevels - 1);
+
+    for (unsigned int y = 0; y < targetCountTilesY; y += step)
+    {
+      for (unsigned int x = 0; x < targetCountTilesX; x += step)
+      {
+        std::auto_ptr<ReconstructPyramidCommand> command;
+        command.reset(new ReconstructPyramidCommand
+                      (target, source, countLevels - 1, x, y, parameters));
+        command->SetShiftTargetLevel(shiftTargetLevel);
+        tasks.Push(command.release());
+      }
+    }
+  }
+}