Mercurial > hg > orthanc-wsi
changeset 62:f45cec2c32e2
Speed-up in the Web viewer plugin
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 25 Nov 2016 18:21:15 +0100 |
parents | 147bd6dc28db |
children | 3252fbf149e3 |
files | Framework/DicomToolbox.cpp Framework/DicomToolbox.h Framework/Inputs/DicomPyramid.cpp Framework/Inputs/DicomPyramidInstance.cpp Framework/Targets/OrthancTarget.cpp NEWS Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.cpp ViewerPlugin/CMakeLists.txt |
diffstat | 8 files changed, 142 insertions(+), 143 deletions(-) [+] |
line wrap: on
line diff
--- a/Framework/DicomToolbox.cpp Fri Nov 25 17:15:55 2016 +0100 +++ b/Framework/DicomToolbox.cpp Fri Nov 25 18:21:15 2016 +0100 @@ -30,8 +30,6 @@ # include <dcmtk/dcmdata/dcsequen.h> #endif -#include <boost/lexical_cast.hpp> - namespace OrthancWSI { namespace DicomToolbox @@ -160,92 +158,5 @@ } } #endif - - - bool GetStringTag(std::string& result, - const Json::Value& simplifiedTags, - const std::string& tagName, - const std::string& defaultValue) - { - if (simplifiedTags.type() != Json::objectValue) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - - if (!simplifiedTags.isMember(tagName)) - { - result = defaultValue; - return false; - } - else if (simplifiedTags[tagName].type() != Json::stringValue) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - else - { - result = simplifiedTags[tagName].asString(); - return true; - } - } - - - std::string GetMandatoryStringTag(const Json::Value& simplifiedTags, - const std::string& tagName) - { - std::string s; - if (GetStringTag(s, simplifiedTags, tagName, "")) - { - return s; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentTag); - } - } - - - const Json::Value& GetSequenceTag(const Json::Value& simplifiedTags, - const std::string& tagName) - { - if (simplifiedTags.type() != Json::objectValue || - !simplifiedTags.isMember(tagName) || - simplifiedTags[tagName].type() != Json::arrayValue) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - - return simplifiedTags[tagName]; - } - - - int GetIntegerTag(const Json::Value& simplifiedTags, - const std::string& tagName) - { - try - { - std::string s = Orthanc::Toolbox::StripSpaces(GetMandatoryStringTag(simplifiedTags, tagName)); - return boost::lexical_cast<int>(s); - } - catch (boost::bad_lexical_cast&) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - } - - - unsigned int GetUnsignedIntegerTag(const Json::Value& simplifiedTags, - const std::string& tagName) - { - int value = GetIntegerTag(simplifiedTags, tagName); - - if (value >= 0) - { - return static_cast<unsigned int>(value); - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - } } }
--- a/Framework/DicomToolbox.h Fri Nov 25 17:15:55 2016 +0100 +++ b/Framework/DicomToolbox.h Fri Nov 25 18:21:15 2016 +0100 @@ -62,22 +62,5 @@ std::string GetStringTag(DcmItem& dataset, const DcmTagKey& key); #endif - - bool GetStringTag(std::string& result, - const Json::Value& simplifiedTags, - const std::string& tagName, - const std::string& defaultValue); - - std::string GetMandatoryStringTag(const Json::Value& simplifiedTags, - const std::string& tagName); - - const Json::Value& GetSequenceTag(const Json::Value& simplifiedTags, - const std::string& tagName); - - int GetIntegerTag(const Json::Value& simplifiedTags, - const std::string& tagName); - - unsigned int GetUnsignedIntegerTag(const Json::Value& simplifiedTags, - const std::string& tagName); } }
--- a/Framework/Inputs/DicomPyramid.cpp Fri Nov 25 17:15:55 2016 +0100 +++ b/Framework/Inputs/DicomPyramid.cpp Fri Nov 25 18:21:15 2016 +0100 @@ -65,12 +65,14 @@ Json::Value series; OrthancPlugins::IOrthancConnection::RestApiGet(series, orthanc_, "/series/" + seriesId); - if (series.type() != Json::objectValue) + if (series.type() != Json::objectValue || + !series.isMember("Instances") || + series["Instances"].type() != Json::arrayValue) { throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); } - const Json::Value& instances = DicomToolbox::GetSequenceTag(series, "Instances"); + const Json::Value& instances = series["Instances"]; instances_.reserve(instances.size()); for (Json::Value::ArrayIndex i = 0; i < instances.size(); i++)
--- a/Framework/Inputs/DicomPyramidInstance.cpp Fri Nov 25 17:15:55 2016 +0100 +++ b/Framework/Inputs/DicomPyramidInstance.cpp Fri Nov 25 18:21:15 2016 +0100 @@ -24,16 +24,24 @@ #include "../../Resources/Orthanc/Core/Logging.h" #include "../../Resources/Orthanc/Core/OrthancException.h" #include "../../Resources/Orthanc/Core/Toolbox.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h" #include "../DicomToolbox.h" #include <cassert> namespace OrthancWSI { - static ImageCompression DetectImageCompression(const Json::Value& header) + static ImageCompression DetectImageCompression(OrthancPlugins::IOrthancConnection& orthanc, + const std::string& instanceId) { + using namespace OrthancPlugins; + + DicomDatasetReader header(new FullOrthancDataset + (orthanc, "/instances/" + instanceId + "/header")); + std::string s = Orthanc::Toolbox::StripSpaces - (DicomToolbox::GetMandatoryStringTag(header, "TransferSyntaxUID")); + (header.GetMandatoryStringValue(DICOM_TAG_TRANSFER_SYNTAX_UID)); if (s == "1.2.840.10008.1.2" || s == "1.2.840.10008.1.2.1") @@ -57,10 +65,12 @@ } - static Orthanc::PixelFormat DetectPixelFormat(const Json::Value& dicom) + static Orthanc::PixelFormat DetectPixelFormat(OrthancPlugins::DicomDatasetReader& reader) { + using namespace OrthancPlugins; + std::string photometric = Orthanc::Toolbox::StripSpaces - (DicomToolbox::GetMandatoryStringTag(dicom, "PhotometricInterpretation")); + (reader.GetMandatoryStringValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION)); if (photometric == "PALETTE") { @@ -68,9 +78,9 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); } - unsigned int bitsStored = DicomToolbox::GetUnsignedIntegerTag(dicom, "BitsStored"); - unsigned int samplesPerPixel = DicomToolbox::GetUnsignedIntegerTag(dicom, "SamplesPerPixel"); - bool isSigned = (DicomToolbox::GetUnsignedIntegerTag(dicom, "PixelRepresentation") != 0); + unsigned int bitsStored = reader.GetUnsignedIntegerValue(DICOM_TAG_BITS_STORED); + unsigned int samplesPerPixel = reader.GetUnsignedIntegerValue(DICOM_TAG_SAMPLES_PER_PIXEL); + bool isSigned = (reader.GetUnsignedIntegerValue(DICOM_TAG_PIXEL_REPRESENTATION) != 0); if (bitsStored == 8 && samplesPerPixel == 1 && @@ -105,12 +115,8 @@ if (!hasCompression_) { - Json::Value header; - OrthancPlugins::IOrthancConnection::RestApiGet - (header, orthanc, "/instances/" + instanceId_ + "/header?simplify"); - + compression_ = DetectImageCompression(orthanc, instanceId_); hasCompression_ = true; - compression_ = DetectImageCompression(header); } return compression_; @@ -122,43 +128,49 @@ instanceId_(instanceId), hasCompression_(false) { - Json::Value dicom; - OrthancPlugins::IOrthancConnection::RestApiGet - (dicom, orthanc, "/instances/" + instanceId + "/tags?simplify"); + using namespace OrthancPlugins; - if (DicomToolbox::GetMandatoryStringTag(dicom, "SOPClassUID") != "1.2.840.10008.5.1.4.1.1.77.1.6" || - DicomToolbox::GetMandatoryStringTag(dicom, "Modality") != "SM") + DicomDatasetReader reader(new FullOrthancDataset(orthanc, "/instances/" + instanceId + "/tags")); + + if (reader.GetMandatoryStringValue(DICOM_TAG_SOP_CLASS_UID) != "1.2.840.10008.5.1.4.1.1.77.1.6" || + reader.GetMandatoryStringValue(DICOM_TAG_MODALITY) != "SM") { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - format_ = DetectPixelFormat(dicom); - tileWidth_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "Columns"); - tileHeight_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "Rows"); - totalWidth_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "TotalPixelMatrixColumns"); - totalHeight_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "TotalPixelMatrixRows"); + format_ = DetectPixelFormat(reader); + tileWidth_ = reader.GetUnsignedIntegerValue(DICOM_TAG_COLUMNS); + tileHeight_ = reader.GetUnsignedIntegerValue(DICOM_TAG_ROWS); + totalWidth_ = reader.GetUnsignedIntegerValue(DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS); + totalHeight_ = reader.GetUnsignedIntegerValue(DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS); - const Json::Value& frames = DicomToolbox::GetSequenceTag(dicom, "PerFrameFunctionalGroupsSequence"); + size_t countFrames; + if (!reader.GetDataset().GetSequenceSize(countFrames, DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } - if (frames.size() != DicomToolbox::GetUnsignedIntegerTag(dicom, "NumberOfFrames")) + if (countFrames != reader.GetUnsignedIntegerValue(DICOM_TAG_NUMBER_OF_FRAMES)) { LOG(ERROR) << "Mismatch between the number of frames in instance: " << instanceId; throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); } - frames_.resize(frames.size()); + frames_.resize(countFrames); - for (Json::Value::ArrayIndex i = 0; i < frames.size(); i++) + for (size_t i = 0; i < countFrames; i++) { - const Json::Value& frame = DicomToolbox::GetSequenceTag(frames[i], "PlanePositionSlideSequence"); - if (frame.size() != 1) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } + int xx = reader.GetIntegerValue(DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i, + DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE, 0, + DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)); + + int yy = reader.GetIntegerValue(DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i, + DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE, 0, + DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)); // "-1", because coordinates are shifted by 1 in DICOM - int xx = DicomToolbox::GetIntegerTag(frame[0], "ColumnPositionInTotalImagePixelMatrix") - 1; - int yy = DicomToolbox::GetIntegerTag(frame[0], "RowPositionInTotalImagePixelMatrix") - 1; + xx -= 1; + yy -= 1; unsigned int x = static_cast<unsigned int>(xx); unsigned int y = static_cast<unsigned int>(yy);
--- a/Framework/Targets/OrthancTarget.cpp Fri Nov 25 17:15:55 2016 +0100 +++ b/Framework/Targets/OrthancTarget.cpp Fri Nov 25 18:21:15 2016 +0100 @@ -40,14 +40,28 @@ Json::Value result; OrthancPlugins::IOrthancConnection::RestApiPost(result, *orthanc_, "/instances", file); - std::string instanceId = DicomToolbox::GetMandatoryStringTag(result, "ID"); + if (result.type() != Json::objectValue || + !result.isMember("ID") || + result["ID"].type() != Json::stringValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + std::string instanceId = result["ID"].asString(); if (first_) { Json::Value instance; OrthancPlugins::IOrthancConnection::RestApiGet(instance, *orthanc_, "/instances/" + instanceId); - std::string seriesId = DicomToolbox::GetMandatoryStringTag(instance, "ParentSeries"); + if (instance.type() != Json::objectValue || + !instance.isMember("ParentSeries") || + instance["ParentSeries"].type() != Json::stringValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + std::string seriesId = instance["ParentSeries"].asString(); LOG(WARNING) << "ID of the whole-slide image series in Orthanc: " << seriesId; first_ = false;
--- a/NEWS Fri Nov 25 17:15:55 2016 +0100 +++ b/NEWS Fri Nov 25 18:21:15 2016 +0100 @@ -1,6 +1,8 @@ Pending changes in the mainline =============================== +* Speed-up in the Web viewer plugin +* Refactorings Version 0.1 (2016/10/28)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.cpp Fri Nov 25 18:21:15 2016 +0100 @@ -0,0 +1,72 @@ +/** + * 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 General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "IOrthancConnection.h" + +#include "OrthancPluginCppWrapper.h" + +#include <json/reader.h> + +namespace OrthancPlugins +{ + void IOrthancConnection::ParseJson(Json::Value& result, + const std::string& content) + { + Json::Reader reader; + + if (!reader.parse(content, result)) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat); + } + } + + + void IOrthancConnection::RestApiGet(Json::Value& result, + IOrthancConnection& orthanc, + const std::string& uri) + { + std::string content; + orthanc.RestApiGet(content, uri); + ParseJson(result, content); + } + + + void IOrthancConnection::RestApiPost(Json::Value& result, + IOrthancConnection& orthanc, + const std::string& uri, + const std::string& body) + { + std::string content; + orthanc.RestApiPost(content, uri, body); + ParseJson(result, content); + } +}
--- a/ViewerPlugin/CMakeLists.txt Fri Nov 25 17:15:55 2016 +0100 +++ b/ViewerPlugin/CMakeLists.txt Fri Nov 25 18:21:15 2016 +0100 @@ -187,6 +187,9 @@ ${ORTHANC_ROOT}/Core/MultiThreading/Semaphore.cpp ${ORTHANC_ROOT}/Core/SystemToolbox.cpp ${ORTHANC_ROOT}/Core/Toolbox.cpp + ${ORTHANC_ROOT}/Plugins/Samples/Common/DicomDatasetReader.cpp + ${ORTHANC_ROOT}/Plugins/Samples/Common/DicomPath.cpp + ${ORTHANC_ROOT}/Plugins/Samples/Common/FullOrthancDataset.cpp ${ORTHANC_ROOT}/Plugins/Samples/Common/IOrthancConnection.cpp ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginConnection.cpp ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp