Mercurial > hg > orthanc
changeset 526:e318e9d49815 dicom-rt
rt-struct
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 29 Aug 2013 17:33:33 +0200 |
parents | 68451838fb2c |
children | bd2087bb6450 |
files | CMakeLists.txt OrthancServer/OrthancRestApi.cpp OrthancServer/OrthancRestApi.h OrthancServer/RadiotherapyRestApi.cpp OrthancServer/RadiotherapyRestApi.h OrthancServer/ServerContext.h OrthancServer/main.cpp |
diffstat | 7 files changed, 235 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Thu Aug 29 15:10:05 2013 +0200 +++ b/CMakeLists.txt Thu Aug 29 17:33:33 2013 +0200 @@ -175,6 +175,8 @@ OrthancServer/ServerContext.cpp OrthancServer/ServerEnumerations.cpp OrthancServer/ServerToolbox.cpp + + OrthancServer/RadiotherapyRestApi.cpp ) # Ensure autogenerated code is built before building ServerLibrary
--- a/OrthancServer/OrthancRestApi.cpp Thu Aug 29 15:10:05 2013 +0200 +++ b/OrthancServer/OrthancRestApi.cpp Thu Aug 29 17:33:33 2013 +0200 @@ -64,11 +64,6 @@ namespace Orthanc { - // TODO IMPROVE MULTITHREADING - // Every call to "ParsedDicomFile" must lock this mutex!!! - static boost::mutex cacheMutex_; - - // DICOM SCU ---------------------------------------------------------------- static void ConnectToModality(DicomUserConnection& connection, @@ -977,9 +972,9 @@ static void GetRawContent(RestApi::GetCall& call) { - boost::mutex::scoped_lock lock(cacheMutex_); + RETRIEVE_CONTEXT(call); + boost::mutex::scoped_lock lock(context.GetDicomFileMutex()); - RETRIEVE_CONTEXT(call); std::string id = call.GetUriComponent("id", ""); ParsedDicomFile& dicom = context.GetDicomFile(id); dicom.SendPathValue(call.GetOutput(), call.GetTrailingUri()); @@ -1260,8 +1255,8 @@ bool removePrivateTags, RestApi::PostCall& call) { - boost::mutex::scoped_lock lock(cacheMutex_); RETRIEVE_CONTEXT(call); + boost::mutex::scoped_lock lock(context.GetDicomFileMutex()); std::string id = call.GetUriComponent("id", ""); ParsedDicomFile& dicom = context.GetDicomFile(id); @@ -1338,8 +1333,8 @@ bool isFirst = true; Json::Value result(Json::objectValue); - boost::mutex::scoped_lock lock(cacheMutex_); RETRIEVE_CONTEXT(call); + boost::mutex::scoped_lock lock(context.GetDicomFileMutex()); Instances instances; std::string id = call.GetUriComponent("id", "");
--- a/OrthancServer/OrthancRestApi.h Thu Aug 29 15:10:05 2013 +0200 +++ b/OrthancServer/OrthancRestApi.h Thu Aug 29 17:33:33 2013 +0200 @@ -44,7 +44,7 @@ public: typedef std::set<std::string> SetOfStrings; - private: + protected: ServerContext& context_; SetOfStrings modalities_; SetOfStrings peers_;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/RadiotherapyRestApi.cpp Thu Aug 29 17:33:33 2013 +0200 @@ -0,0 +1,169 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2013 Medical Physics Department, CHU 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 "RadiotherapyRestApi.h" + +#include "ServerToolbox.h" + +#define RETRIEVE_CONTEXT(call) \ + OrthancRestApi& contextApi = \ + dynamic_cast<OrthancRestApi&>(call.GetContext()); \ + ServerContext& context = contextApi.GetContext() + + +#define REFERENCED_STUDY_SEQUENCE "0008,1110" +#define REFERENCED_SOP_INSTANCE_UID "0008,1155" +#define FRAME_OF_REFERENCE_UID "0020,0052" +#define REFERENCED_FRAME_OF_REFERENCE_SEQUENCE "3006,0010" + +namespace Orthanc +{ + static bool CheckSeriesModality(Json::Value& study, + Json::Value& series, + Json::Value& content, + ServerContext& context, + const std::string& seriesId, + const std::string& modality) + { + if (!context.GetIndex().LookupResource(series, seriesId, ResourceType_Series)) + { + return false; + } + + // Retrieve the parent study + std::string studyId = series["ParentStudy"].asString(); + if (!context.GetIndex().LookupResource(study, studyId, ResourceType_Study)) + { + return false; + } + + // Check the modality and that there is a single instance inside the series + if (!series["MainDicomTags"].isMember("Modality") || + series["MainDicomTags"]["Modality"].asString() != modality || + series["Instances"].size() != 1) + { + return false; + } + + // Retrieve the instance data + std::string instanceId = series["Instances"][0].asString(); + + Json::Value info; + context.ReadJson(content, instanceId); + + return true; + } + + + static bool GetRtStructuresInfo(Json::Value& study, + Json::Value& series, + Json::Value& content, + std::string& frameOfReference, + ServerContext& context, + const std::string& seriesId) + { + if (!CheckSeriesModality(study, series, content, context, seriesId, "RTSTRUCT")) + { + return false; + } + + // Check that the "ReferencedStudySequence" is the same as the parent study. + if (!content.isMember(REFERENCED_STUDY_SEQUENCE) || + content[REFERENCED_STUDY_SEQUENCE]["Value"].size() != 1 || + !content[REFERENCED_STUDY_SEQUENCE]["Value"][0].isMember(REFERENCED_SOP_INSTANCE_UID) || + content[REFERENCED_STUDY_SEQUENCE]["Value"][0][REFERENCED_SOP_INSTANCE_UID]["Value"].asString() != + study["MainDicomTags"]["StudyInstanceUID"].asString()) + { + return false; + } + + // Lookup for the frame of reference. Orthanc does not support + // RTSTRUCT with multiple frames of reference. + if (!content.isMember(REFERENCED_FRAME_OF_REFERENCE_SEQUENCE) || + content[REFERENCED_FRAME_OF_REFERENCE_SEQUENCE]["Value"].size() != 1 || + !content[REFERENCED_FRAME_OF_REFERENCE_SEQUENCE]["Value"][0].isMember(FRAME_OF_REFERENCE_UID)) + { + return false; + } + + frameOfReference = content[REFERENCED_FRAME_OF_REFERENCE_SEQUENCE]["Value"][0][FRAME_OF_REFERENCE_UID]["Value"].asString(); + + return true; + } + + + static void GetRtStructuresInfo(RestApi::GetCall& call) + { + RETRIEVE_CONTEXT(call); + + Json::Value study, series, content; + std::string frameOfReference; + if (GetRtStructuresInfo(study, series, content, frameOfReference, context, call.GetUriComponent("id", ""))) + { + Json::Value result; + + result["Study"] = study["ID"]; + + + // Lookup the series with the same frame of reference inside this study + result["RelatedSeries"] = Json::arrayValue; + + for (Json::Value::ArrayIndex i = 0; i < study["Series"].size(); i++) + { + Json::Value otherSeries; + if (context.GetIndex().LookupResource(otherSeries, study["Series"][i].asString(), ResourceType_Series) && + otherSeries["Instances"].size() > 0) + { + Json::Value info; + context.ReadJson(info, otherSeries["Instances"][0].asString()); + + if (info.isMember(FRAME_OF_REFERENCE_UID)) + { + result["RelatedSeries"].append(study["Series"][i].asString()); + } + } + } + + call.GetOutput().AnswerJson(result); + } + } + + + RadiotherapyRestApi::RadiotherapyRestApi(ServerContext& context) : OrthancRestApi(context) + { + Register("/series/{id}/rt-structures", GetRtStructuresInfo); + } +} + + +// curl http://localhost:8042/series/0b9e2bb2-605a59aa-f27c0260-9cc4faf6-9d8bf457/rt-structures +// curl http://localhost:8042/series/ef041e6b-c855e775-f7e0f7fe-dc3c17dc-533cb8c5/rt-structures
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/RadiotherapyRestApi.h Thu Aug 29 17:33:33 2013 +0200 @@ -0,0 +1,44 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2013 Medical Physics Department, CHU 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/>. + **/ + + +#pragma once + +#include "OrthancRestApi.h" + +namespace Orthanc +{ + class RadiotherapyRestApi : public OrthancRestApi + { + public: + RadiotherapyRestApi(ServerContext& context); + }; +}
--- a/OrthancServer/ServerContext.h Thu Aug 29 15:10:05 2013 +0200 +++ b/OrthancServer/ServerContext.h Thu Aug 29 17:33:33 2013 +0200 @@ -40,6 +40,8 @@ #include "ServerIndex.h" #include "FromDcmtkBridge.h" +#include <boost/thread.hpp> + namespace Orthanc { /** @@ -63,6 +65,8 @@ virtual IDynamicObject* Provide(const std::string& id); }; + boost::mutex cacheMutex_; + FileStorage storage_; ServerIndex index_; CompressedFileStorageAccessor accessor_; @@ -133,6 +137,13 @@ // TODO IMPLEMENT MULTITHREADING FOR THIS METHOD ParsedDicomFile& GetDicomFile(const std::string& instancePublicId); + boost::mutex& GetDicomFileMutex() + { + // TODO IMPROVE MULTITHREADING + // Every call to "ParsedDicomFile" must lock this mutex!!! + return cacheMutex_; + } + LuaContext& GetLuaContext() { return lua_;
--- a/OrthancServer/main.cpp Thu Aug 29 15:10:05 2013 +0200 +++ b/OrthancServer/main.cpp Thu Aug 29 17:33:33 2013 +0200 @@ -30,7 +30,8 @@ **/ -#include "OrthancRestApi.h" +//#include "OrthancRestApi.h" +#include "RadiotherapyRestApi.h" #include <fstream> #include <glog/logging.h> @@ -411,7 +412,8 @@ httpServer.RegisterHandler(new FilesystemHttpHandler("/app", ORTHANC_PATH "/OrthancExplorer")); #endif - httpServer.RegisterHandler(new OrthancRestApi(context)); + //httpServer.RegisterHandler(new OrthancRestApi(context)); + httpServer.RegisterHandler(new RadiotherapyRestApi(context)); // GO !!! httpServer.Start();