Mercurial > hg > orthanc-wsi
diff Framework/DicomizerParameters.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/DicomizerParameters.cpp Sat Oct 22 21:48:33 2016 +0200 @@ -0,0 +1,274 @@ +/** + * 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 "DicomizerParameters.h" + +#include "Messaging/FolderTarget.h" +#include "Messaging/OrthancTarget.h" + +#include "Orthanc/Core/OrthancException.h" + +#include <boost/thread.hpp> +#include <boost/lexical_cast.hpp> + +namespace OrthancWSI +{ + static unsigned int ChooseNumberOfThreads() + { + unsigned int nthreads = boost::thread::hardware_concurrency(); + + if (nthreads % 2 == 0) + { + nthreads = nthreads / 2; + } + else + { + nthreads = nthreads / 2 + 1; + } + + if (nthreads == 0) + { + nthreads = 1; + } + + return nthreads; + } + + + DicomizerParameters::DicomizerParameters() + { + safetyCheck_ = false; + repaintBackground_ = false; + backgroundColor_[0] = 255; + backgroundColor_[1] = 255; + backgroundColor_[2] = 255; + targetCompression_ = ImageCompression_Jpeg; + hasTargetTileSize_ = false; + threadsCount_ = ChooseNumberOfThreads(); + maxDicomFileSize_ = 10 * 1024 * 1024; // 10MB + reconstructPyramid_ = false; + pyramidLevelsCount_ = 0; + pyramidLowerLevelsCount_ = 0; + smooth_ = false; + jpegQuality_ = 90; + forceReencode_ = false; + opticalPath_ = OpticalPath_Brightfield; + } + + + void DicomizerParameters::SetBackgroundColor(uint8_t red, + uint8_t green, + uint8_t blue) + { + repaintBackground_ = true; + backgroundColor_[0] = red; + backgroundColor_[1] = green; + backgroundColor_[2] = blue; + } + + + void DicomizerParameters::SetTargetTileSize(unsigned int width, + unsigned int height) + { + hasTargetTileSize_ = true; + targetTileWidth_ = width; + targetTileHeight_ = height; + } + + + unsigned int DicomizerParameters::GetTargetTileWidth(unsigned int defaultWidth) const + { + if (hasTargetTileSize_ && + targetTileWidth_ != 0) + { + return targetTileWidth_; + } + else + { + return defaultWidth; + } + } + + + unsigned int DicomizerParameters::GetTargetTileHeight(unsigned int defaultHeight) const + { + if (hasTargetTileSize_ && + targetTileHeight_ != 0) + { + return targetTileHeight_; + } + else + { + return defaultHeight; + } + } + + + void DicomizerParameters::SetThreadsCount(unsigned int threads) + { + if (threads == 0) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + threadsCount_ = threads; + } + + + void DicomizerParameters::SetDicomMaxFileSize(unsigned int size) + { + if (size <= 1024) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + maxDicomFileSize_ = size; + } + + + void DicomizerParameters::SetPyramidLevelsCount(unsigned int count) + { + if (count <= 0) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + pyramidLevelsCount_ = count; + } + + + unsigned int DicomizerParameters::GetPyramidLevelsCount(const IPyramidWriter& target, + const ITiledPyramid& source) const + { + if (!reconstructPyramid_) + { + // Only makes sense if reconstructing the pyramid + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + if (pyramidLevelsCount_ != 0) + { + return pyramidLevelsCount_; + } + + // By default, the number of levels for the pyramid is taken so that + // the upper level is reduced either to 1 column of tiles, or to 1 + // row of tiles. + unsigned int totalWidth = source.GetLevelWidth(0); + unsigned int totalHeight = source.GetLevelHeight(0); + + unsigned int countLevels = 1; + for (;;) + { + unsigned int zoom = 1 << (countLevels - 1); + + if (CeilingDivision(totalWidth, zoom) <= target.GetTileWidth() || + CeilingDivision(totalHeight, zoom) <= target.GetTileHeight()) + { + break; + } + + countLevels += 1; + } + + return countLevels; + } + + + void DicomizerParameters::SetPyramidLowerLevelsCount(unsigned int count) + { + if (count <= 0) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + pyramidLowerLevelsCount_ = count; + } + + + unsigned int DicomizerParameters::GetPyramidLowerLevelsCount(const IPyramidWriter& target, + const ITiledPyramid& source) const + { + if (!reconstructPyramid_) + { + // Only makes sense if reconstructing the pyramid + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + if (pyramidLowerLevelsCount_ != 0) + { + return pyramidLowerLevelsCount_; + } + + unsigned int fullNumberOfTiles = ( + CeilingDivision(source.GetLevelWidth(0), source.GetTileWidth()) * + CeilingDivision(source.GetLevelHeight(0), source.GetTileHeight())); + + // By default, the number of lower levels in the pyramid is chosen + // as a compromise between the number of tasks (there should not be + // too few tasks, otherwise multithreading would not be efficient) + // and memory consumption (maximum 64MB of RAM due to the decoding + // of the tiles of the source image per thread: cf. PyramidReader). + unsigned int result = 1; + for (;;) + { + unsigned int zoom = 1 << (result - 1); + unsigned int numberOfTiles = CeilingDivision(fullNumberOfTiles, zoom * zoom); + + if (result + 1 > target.GetLevelCount() || + numberOfTiles < 4 * GetThreadsCount() || + zoom * target.GetTileWidth() > 4096 || + zoom * target.GetTileHeight() > 4096) + { + break; + } + + result += 1; + } + + return result - 1; + } + + + void DicomizerParameters::SetJpegQuality(int quality) + { + if (quality <= 0 || + quality > 100) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + jpegQuality_ = quality; + } + + + IFileTarget* DicomizerParameters::CreateTarget() const + { + if (folder_.empty() || + folderPattern_.empty()) + { + return new OrthancTarget(orthanc_); + } + else + { + return new FolderTarget(folder_ + "/" + folderPattern_); + } + } +}