diff --git a/Modules/DICOMweb/CMakeLists.txt b/Modules/DICOMweb/CMakeLists.txt new file mode 100644 index 0000000000..d503d99cfe --- /dev/null +++ b/Modules/DICOMweb/CMakeLists.txt @@ -0,0 +1,3 @@ +mitk_create_module(DEPENDS MitkCore + MitkREST MitkRESTService) + diff --git a/Modules/DICOMweb/files.cmake b/Modules/DICOMweb/files.cmake new file mode 100644 index 0000000000..adba99da21 --- /dev/null +++ b/Modules/DICOMweb/files.cmake @@ -0,0 +1,3 @@ +set(CPP_FILES + mitkDICOMweb.cpp +) diff --git a/Modules/DICOMweb/include/mitkDICOMweb.h b/Modules/DICOMweb/include/mitkDICOMweb.h new file mode 100644 index 0000000000..8fdc321f4e --- /dev/null +++ b/Modules/DICOMweb/include/mitkDICOMweb.h @@ -0,0 +1,141 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkDICOMweb_h +#define mitkDICOMweb_h + +#include + +#include "cpprest/asyncrt_utils.h" +#include "cpprest/http_client.h" +#include +#include +#include +#include + +#include +#include + +/** + * @brief This class represents the implementation of the RESTful DICOMweb standard + * (http://dicom.nema.org/medical/dicom/current/output/html/part18.html). It is used to communicate DICOM data over HTTP + * to a DICOMweb enabled PACS server. + * + * @author Tobias Stein + */ + +namespace mitk +{ + + class MITKDICOMWEB_EXPORT DICOMweb + { + public: + typedef web::http::uri_builder MitkUriBuilder; + typedef web::http::http_request MitkRequest; + typedef web::http::http_response MitkResponse; + typedef web::http::methods MitkRESTMethods; + + DICOMweb(); + + /** + * @brief Creates a DICOMweb service instance which allow basic DICOM operations on the given base URI. + * + * @param baseURI the uri for the PACS server: for example a dcm4chee + * http:///dcm4chee-arc/aets/DCM4CHEE/ + */ + DICOMweb(utility::string_t baseURI); + + /** + * @brief Sends a STOW request with the file in the given path to the study given bei its UID. + * + * @param filePath the path to a valid DICOM file which should be send + * @param studyUID the DICOM study uid + * @param the task to wait for + */ + pplx::task SendSTOW(utility::string_t filePath, utility::string_t studyUID); + + /** + * @brief Sends a WADO request for an DICOM object instance matching the given uid parameters and stores it at the + * given file path. + * + * @param filePath the path at which the retrieved DICOM object instance will be stored + * @param studyUID the DICOM study uid + * @param seriesUID the DICOM series uid + * @param instanceUID the DICOM instance uid + * @return the task to wait for, which unfolds no value when finished + */ + pplx::task SendWADO(utility::string_t filePath, + utility::string_t studyUID, + utility::string_t seriesUID, + utility::string_t instanceUID); + + /** + * @brief Sends a WADO request for an DICOM object series matching the given uid parameters and stores all the + * containing instances at the given folder path. + * + * @param folderPath the path at which the retrieved DICOM object instances of the retrieved series will be stored + * @param studyUID the DICOM study uid + * @param seriesUID the DICOM series uid + * @return the task to wait for, which unfolds the name of the first DICOM object file within the folder path + */ + pplx::task SendWADO(utility::string_t folderPath, + utility::string_t studyUID, + utility::string_t seriesUID); + + /** + * @brief Sends a QIDO request containing the given parameters to filter the query. + * + * Example Map: + * + * mitk::RESTUtil::ParamMap seriesInstancesParams; + * seriesInstancesParams.insert(mitk::RESTUtil::ParamMap::value_type(U("limit"), U("1"))); + * + * + * @param map the map of parameters to filter the query + * @return the task to wait for, which unfolds the result JSON response for the request when finished + */ + pplx::task SendQIDO(mitk::RESTUtil::ParamMap map); + + private: + /** + * @brief Creates a QIDO request URI with the given parameter map + */ + utility::string_t CreateQIDOUri(mitk::RESTUtil::ParamMap map); + + /** + * @brief Creates a WADO request URI with the given parameter + */ + utility::string_t CreateWADOUri(utility::string_t studyUID, + utility::string_t seriesUID, + utility::string_t instanceUID); + + /** + * @brief Creates a STOW request URI with the study uid + */ + utility::string_t CreateSTOWUri(utility::string_t studyUID); + + /** + * @brief Initializes the rest manager for this service instance. Should be called in constructor to make sure the + * public API can work properly. + */ + void InitializeRESTManager(); + + utility::string_t m_BaseURI; + mitk::IRESTManager *m_RESTManager; + }; +} + +#endif // DICOMweb_h diff --git a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/DICOMweb.cpp b/Modules/DICOMweb/src/mitkDICOMweb.cpp similarity index 89% rename from Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/DICOMweb.cpp rename to Modules/DICOMweb/src/mitkDICOMweb.cpp index a886d82e08..c476a585d1 100644 --- a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/DICOMweb.cpp +++ b/Modules/DICOMweb/src/mitkDICOMweb.cpp @@ -1,219 +1,219 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#include "DICOMweb.h" +#include "mitkDICOMweb.h" -DICOMweb::DICOMweb() {} +mitk::DICOMweb::DICOMweb() {} -DICOMweb::DICOMweb(utility::string_t baseURI) : m_BaseURI(baseURI) +mitk::DICOMweb::DICOMweb(utility::string_t baseURI) : m_BaseURI(baseURI) { MITK_INFO << "base uri: " << mitk::RESTUtil::convertToUtf8(m_BaseURI); InitializeRESTManager(); } -utility::string_t DICOMweb::CreateQIDOUri(mitk::RESTUtil::ParamMap map) +utility::string_t mitk::DICOMweb::CreateQIDOUri(mitk::RESTUtil::ParamMap map) { MitkUriBuilder queryBuilder(m_BaseURI + U("rs/instances")); for (auto const &element : map) { queryBuilder.append_query(element.first, element.second); } return queryBuilder.to_string(); } -utility::string_t DICOMweb::CreateWADOUri(utility::string_t studyUID, +utility::string_t mitk::DICOMweb::CreateWADOUri(utility::string_t studyUID, utility::string_t seriesUID, utility::string_t instanceUID) { MitkUriBuilder builder(m_BaseURI + U("wado")); builder.append_query(U("requestType"), U("WADO")); builder.append_query(U("studyUID"), studyUID); builder.append_query(U("seriesUID"), seriesUID); builder.append_query(U("objectUID"), instanceUID); builder.append_query(U("contentType"), U("application/dicom")); return builder.to_string(); } -utility::string_t DICOMweb::CreateSTOWUri(utility::string_t studyUID) +utility::string_t mitk::DICOMweb::CreateSTOWUri(utility::string_t studyUID) { MitkUriBuilder builder(m_BaseURI + U("rs/studies")); builder.append_path(studyUID); return builder.to_string(); } -pplx::task DICOMweb::SendSTOW(utility::string_t filePath, utility::string_t studyUID) +pplx::task mitk::DICOMweb::SendSTOW(utility::string_t filePath, utility::string_t studyUID) { auto uri = CreateSTOWUri(studyUID); // this is the working stow-rs request which supports just one dicom file packed into a multipart message std::ifstream input(filePath, std::ios::binary); if (!input) { MITK_WARN << "could not read file to POST"; return pplx::task(); } std::vector result; std::vector buffer; // Stop eating new lines in binary mode!!! input.unsetf(std::ios::skipws); input.seekg(0, std::ios::end); const std::streampos fileSize = input.tellg(); input.seekg(0, std::ios::beg); MITK_INFO << fileSize << " bytes will be sent."; buffer.reserve(fileSize); // file size std::copy( std::istream_iterator(input), std::istream_iterator(), std::back_inserter(buffer)); // in future more than one file should also be supported.. std::string head = ""; head += "\r\n--boundary"; head += "\r\nContent-Type: " + mitk::RESTUtil::convertToUtf8(U("application/dicom")) + "\r\n\r\n"; std::vector bodyVector(head.begin(), head.end()); std::string tail = ""; tail += "\r\n--boundary--"; result.insert(result.end(), bodyVector.begin(), bodyVector.end()); result.insert(result.end(), buffer.begin(), buffer.end()); result.insert(result.end(), tail.begin(), tail.end()); mitk::RESTUtil::ParamMap headers; headers.insert(mitk::RESTUtil::ParamMap::value_type( U("Content-Type"), U("multipart/related; type=\"application/dicom\"; boundary=boundary"))); try { return m_RESTManager->SendRequest(uri, mitk::IRESTManager::RequestType::Post, &result, headers) .then([=](web::json::value result) { if (result.is_null()) { } }); } catch (std::exception &e) { MITK_WARN << e.what(); } return pplx::task(); } -pplx::task DICOMweb::SendWADO(utility::string_t filePath, +pplx::task mitk::DICOMweb::SendWADO(utility::string_t filePath, utility::string_t studyUID, utility::string_t seriesUID, utility::string_t instanceUID) { auto uri = CreateWADOUri(studyUID, seriesUID, instanceUID); // don't want return something auto content = web::json::value(); return m_RESTManager->SendRequest(uri, mitk::IRESTManager::RequestType::Get, &content, {}, filePath) .then([=](web::json::value result) { if (result.is_null()) { } }); } -pplx::task DICOMweb::SendWADO(utility::string_t folderPath, +pplx::task mitk::DICOMweb::SendWADO(utility::string_t folderPath, utility::string_t studyUID, utility::string_t seriesUID) { mitk::RESTUtil::ParamMap seriesInstances; seriesInstances.insert(mitk::RESTUtil::ParamMap::value_type(U("StudyInstanceUID"), studyUID)); seriesInstances.insert(mitk::RESTUtil::ParamMap::value_type(U("SeriesInstanceUID"), seriesUID)); return SendQIDO(seriesInstances).then([=](web::json::value jsonResult) -> pplx::task { auto jsonListResult = jsonResult; auto resultArray = jsonListResult.as_array(); auto firstFileName = std::string(); std::vector> tasks; for (unsigned short i = 0; i < resultArray.size(); i++) { try { auto firstResult = resultArray[i]; auto sopInstanceUIDKey = firstResult.at(U("00080018")); auto sopInstanceObject = sopInstanceUIDKey.as_object(); auto valueKey = sopInstanceObject.at(U("Value")); auto valueArray = valueKey.as_array(); auto sopInstanceUID = valueArray[0].as_string(); auto fileName = utility::string_t(sopInstanceUID).append(U(".dcm")); // save first file name as result to load series if (i == 0) { firstFileName = utility::conversions::to_utf8string(fileName); } auto filePath = utility::string_t(folderPath).append(fileName); auto task = SendWADO(filePath, studyUID, seriesUID, sopInstanceUID); tasks.push_back(task); } catch (const web::json::json_exception &e) { MITK_ERROR << e.what(); } } auto joinTask = pplx::when_all(begin(tasks), end(tasks)); auto returnTask = joinTask.then([=](void) -> std::string { auto folderPathUtf8 = utility::conversions::to_utf8string(folderPath); auto result = folderPathUtf8 + firstFileName; return result; }); return returnTask; }); } -pplx::task DICOMweb::SendQIDO(mitk::RESTUtil::ParamMap map) +pplx::task mitk::DICOMweb::SendQIDO(mitk::RESTUtil::ParamMap map) { auto uri = CreateQIDOUri(map); mitk::RESTUtil::ParamMap headers; headers.insert(mitk::RESTUtil::ParamMap::value_type(U("Accept"), U("application/json"))); auto content = web::json::value(); return m_RESTManager->SendRequest(uri, mitk::IRESTManager::RequestType::Get, &content, headers); } -void DICOMweb::InitializeRESTManager() +void mitk::DICOMweb::InitializeRESTManager() { auto *context = us::GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { m_RESTManager = managerService; } } } diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index 798e7de029..9ba50d8efc 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,88 +1,89 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(MITK_MODULES Core CommandLine AppUtil RDF LegacyIO DataTypesExt Annotation LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMReaderServices DICOMQI DICOMTesting SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction SceneSerialization Gizmo GraphAlgorithms Multilabel Chart ImageStatistics ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation QtWidgets QtWidgetsExt ImageStatisticsUI SegmentationUI MatchPointRegistration MatchPointRegistrationUI Classification GPGPU OpenIGTLink IGTBase IGT CameraCalibration OpenCL OpenCVVideoSupport QtOverlays ToFHardware ToFProcessing ToFUI PhotoacousticsHardware PhotoacousticsAlgorithms PhotoacousticsLib US USUI DicomUI Remeshing Python QtPython Persistence OpenIGTLinkUI IGTUI DicomRT RTUI IOExt XNAT TubeGraph BiophotonicsHardware DiffusionImaging TumorInvasionAnalysis BoundingShape RenderWindowManager RenderWindowManagerUI SemanticRelations SemanticRelationsUI CEST BasicImageProcessing ModelFit ModelFitUI Pharmacokinetics PharmacokineticsUI REST RESTService + DICOMweb ) if(MITK_ENABLE_PIC_READER) list(APPEND MITK_MODULES IpPicSupportIO) endif() diff --git a/Modules/REST/include/mitkRESTClient.h b/Modules/REST/include/mitkRESTClient.h index 0c9b9cfa2a..191cc6b7dc 100644 --- a/Modules/REST/include/mitkRESTClient.h +++ b/Modules/REST/include/mitkRESTClient.h @@ -1,104 +1,105 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkRESTClient_h #define mitkRESTClient_h #include #include namespace mitk { class MITKREST_EXPORT RESTClient { public: + using http_request = web::http::http_request; RESTClient(); ~RESTClient(); /** * @brief Executes a HTTP GET request with the given uri and returns a task waiting for a json object * * @throw mitk::Exception if request went wrong * @param uri the URI resulting the target of the HTTP request * @param the additional headers to be set to the HTTP request * @return task to wait for with resulting json object */ pplx::task Get(const web::uri &uri, const std::map headers); /** * @brief Executes a HTTP GET request with the given uri and and stores the byte stream in a file given by the * filePath * * @throw mitk::Exception if request went wrong * @param uri the URI resulting the target of the HTTP request * @param the additional headers to be set to the HTTP request * @return task to wait for returning an empty json object */ pplx::task Get(const web::uri &uri, const utility::string_t &filePath, const std::map headers); /** * @brief Executes a HTTP PUT request with given uri and the content given as json * * @throw mitk::Exception if request went wrong * @param uri defines the URI resulting the target of the HTTP request * @param content the content as json value which should be the body of the request and thus the content of the * created resources * @return task to wait for with resulting json object */ pplx::task Put(const web::uri &uri, const web::json::value *content); /** * @brief Executes a HTTP POST request with given uri and the content given as json * * @throw mitk::Exception if request went wrong * @param uri defines the URI resulting the target of the HTTP request * @param content the content as json value which should be the body of the request and thus the content of the * created resource * @param headers the additional headers to be set to the HTTP request * @return task to wait for with resulting json object */ pplx::task Post(const web::uri &uri, const web::json::value *content, const std::map headers); /** * @brief Executes a HTTP POST request with given uri and the content given as json * * @throw mitk::Exception if request went wrong * @param uri defines the URI resulting the target of the HTTP request * @param content the content as json value which should be the body of the request and thus the content of the * created resource * @param headers the additional headers to be set to the HTTP request * @return task to wait for with resulting json object */ pplx::task Post(const web::uri &uri, const std::vector *content, const std::map headers); private: /** * @brief Use this to create and init a new request with the given headers. If needed, set the body on the resulting * request object to avoid an automatic change of the content type header when setting the body first. */ http_request InitRequest(const std::map headers); pplx::task ExecutePost(const web::uri &uri, http_request request); }; } // namespace mitk #endif diff --git a/Plugins/org.mitk.gui.qt.segmentation.rework/CMakeLists.txt b/Plugins/org.mitk.gui.qt.segmentation.rework/CMakeLists.txt index 29d5736b38..c8281eda51 100644 --- a/Plugins/org.mitk.gui.qt.segmentation.rework/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.segmentation.rework/CMakeLists.txt @@ -1,8 +1,8 @@ project(org_mitk_gui_qt_segmentation_rework) mitk_create_plugin( EXPORT_DIRECTIVE REWORK_EXPORT EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDS MitkQtWidgetsExt MitkREST MitkRESTService MitkChart MitkSegmentationUI + MODULE_DEPENDS MitkQtWidgetsExt MitkREST MitkRESTService MitkDICOMweb MitkChart MitkSegmentationUI PACKAGE_DEPENDS PUBLIC CTK|CTKWidgets ) diff --git a/Plugins/org.mitk.gui.qt.segmentation.rework/files.cmake b/Plugins/org.mitk.gui.qt.segmentation.rework/files.cmake index cd9d2c5a59..75d0af38e0 100644 --- a/Plugins/org.mitk.gui.qt.segmentation.rework/files.cmake +++ b/Plugins/org.mitk.gui.qt.segmentation.rework/files.cmake @@ -1,47 +1,46 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES org_mitk_gui_qt_segmentation_rework_Activator.cpp SegmentationReworkView.cpp ReworkRequestHandler.cpp - DICOMweb.cpp ) set(UI_FILES src/internal/SegmentationReworkViewControls.ui ) set(MOC_H_FILES src/internal/org_mitk_gui_qt_segmentation_rework_Activator.h src/internal/SegmentationReworkView.h src/internal/ReworkRequestHandler.h - src/internal/DICOMweb.h + ) # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench set(CACHED_RESOURCE_FILES resources/icon.xpm resources/plugin_icon.png plugin.xml ) # list of Qt .qrc files which contain additional resources # specific to this plugin set(QRC_FILES ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/DICOMweb.h b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/DICOMweb.h deleted file mode 100644 index 3a210228d0..0000000000 --- a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/DICOMweb.h +++ /dev/null @@ -1,134 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef DICOMweb_h -#define DICOMweb_h - -#include "cpprest/asyncrt_utils.h" -#include "cpprest/http_client.h" -#include -#include -#include -#include - -#include -#include - -/** - * @brief This class represents the implementation of the RESTful DICOMweb standard - * (http://dicom.nema.org/medical/dicom/current/output/html/part18.html). It is used to communicate DICOM data over HTTP - * to a DICOMweb enabled PACS server. - * - * @author Tobias Stein - */ -class DICOMweb -{ -public: - typedef web::http::uri_builder MitkUriBuilder; - typedef web::http::http_request MitkRequest; - typedef web::http::http_response MitkResponse; - typedef web::http::methods MitkRESTMethods; - - DICOMweb(); - - /** - * @brief Creates a DICOMweb service instance which allow basic DICOM operations on the given base URI. - * - * @param baseURI the uri for the PACS server: for example a dcm4chee - * http:///dcm4chee-arc/aets/DCM4CHEE/ - */ - DICOMweb(utility::string_t baseURI); - - /** - * @brief Sends a STOW request with the file in the given path to the study given bei its UID. - * - * @param filePath the path to a valid DICOM file which should be send - * @param studyUID the DICOM study uid - * @param the task to wait for - */ - pplx::task SendSTOW(utility::string_t filePath, utility::string_t studyUID); - - /** - * @brief Sends a WADO request for an DICOM object instance matching the given uid parameters and stores it at the - * given file path. - * - * @param filePath the path at which the retrieved DICOM object instance will be stored - * @param studyUID the DICOM study uid - * @param seriesUID the DICOM series uid - * @param instanceUID the DICOM instance uid - * @return the task to wait for, which unfolds no value when finished - */ - pplx::task SendWADO(utility::string_t filePath, - utility::string_t studyUID, - utility::string_t seriesUID, - utility::string_t instanceUID); - - /** - * @brief Sends a WADO request for an DICOM object series matching the given uid parameters and stores all the - * containing instances at the given folder path. - * - * @param folderPath the path at which the retrieved DICOM object instances of the retrieved series will be stored - * @param studyUID the DICOM study uid - * @param seriesUID the DICOM series uid - * @return the task to wait for, which unfolds the name of the first DICOM object file within the folder path - */ - pplx::task SendWADO(utility::string_t folderPath, - utility::string_t studyUID, - utility::string_t seriesUID); - - /** - * @brief Sends a QIDO request containing the given parameters to filter the query. - * - * Example Map: - * - * mitk::RESTUtil::ParamMap seriesInstancesParams; - * seriesInstancesParams.insert(mitk::RESTUtil::ParamMap::value_type(U("limit"), U("1"))); - * - * - * @param map the map of parameters to filter the query - * @return the task to wait for, which unfolds the result JSON response for the request when finished - */ - pplx::task SendQIDO(mitk::RESTUtil::ParamMap map); - -private: - /** - * @brief Creates a QIDO request URI with the given parameter map - */ - utility::string_t CreateQIDOUri(mitk::RESTUtil::ParamMap map); - - /** - * @brief Creates a WADO request URI with the given parameter - */ - utility::string_t CreateWADOUri(utility::string_t studyUID, - utility::string_t seriesUID, - utility::string_t instanceUID); - - /** - * @brief Creates a STOW request URI with the study uid - */ - utility::string_t CreateSTOWUri(utility::string_t studyUID); - - /** - * @brief Initializes the rest manager for this service instance. Should be called in constructor to make sure the - * public API can work properly. - */ - void InitializeRESTManager(); - - utility::string_t m_BaseURI; - mitk::IRESTManager *m_RESTManager; -}; - -#endif // DICOMweb_h diff --git a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/ReworkRequestHandler.cpp b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/ReworkRequestHandler.cpp index 8c76fb08ed..ad108a059e 100644 --- a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/ReworkRequestHandler.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/ReworkRequestHandler.cpp @@ -1,300 +1,300 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include "ReworkRequestHandler.h" #include #include #include US_INITIALIZE_MODULE ReworkRequestHandler::ReworkRequestHandler() {} ReworkRequestHandler::ReworkRequestHandler(std::string downloadDir, utility::string_t pacsURI) : m_DownloadDir{downloadDir} { - m_DicomWeb = DICOMweb(pacsURI + U("/dcm4chee-arc/aets/DCM4CHEE/")); + m_DicomWeb = mitk::DICOMweb(pacsURI + U("/dcm4chee-arc/aets/DCM4CHEE/")); } ReworkRequestHandler::DicomDTO ReworkRequestHandler::ExtractDTO(const web::json::value &data) { DicomDTO dto; auto messageTypeKey = data.at(U("messageType")); if (messageTypeKey.as_string() == U("downloadData")) { MITK_INFO << "within extract dto"; auto imageStudyUIDKey = data.at(U("studyUID")); auto srSeriesUIDKey = data.at(U("srSeriesUID")); auto groundTruthKey = data.at(U("groundTruth")); auto simScoreKey = data.at(U("simScoreArray")); auto minSliceStartKey = data.at(U("minSliceStart")); dto.srSeriesUID = srSeriesUIDKey.as_string(); dto.groundTruth = groundTruthKey.as_string(); dto.studyUID = imageStudyUIDKey.as_string(); dto.minSliceStart = minSliceStartKey.as_integer(); std::vector vec; web::json::array simArray = simScoreKey.as_array(); for (web::json::value score : simArray) { vec.push_back(score.as_double() * 100); } dto.simScoreArray = vec; } return dto; } web::http::http_response ReworkRequestHandler::Notify(const web::uri &uri, const web::json::value &data, const web::http::method &method) { MITK_INFO << "Incoming notify"; if (method == web::http::methods::GET) { return HandleGet(uri, data); } else if (method == web::http::methods::PUT) { return HandlePut(uri, data); } else if (method == web::http::methods::OPTIONS) { return HandleOptions(uri, data); } web::http::http_response response(web::http::status_codes::BadGateway); response.set_body(U("No one can handle http method from request")); // TODO: include method name return response; } web::http::http_response ReworkRequestHandler::HandlePut(const web::uri &uri, const web::json::value &data) { if (uri.to_string() != U("/inject")) // avoid unused warning MITK_INFO << "no inject path"; emit InvokeProgress(20, {"display graph and query structured report"}); if (data == web::json::value()) { MITK_INFO << "no data in body"; web::http::http_response response(web::http::status_codes::BadRequest); response.set_body(U("No data in body of request")); // TODO: include method name return response; } MITK_INFO << mitk::RESTUtil::convertToUtf8(data.serialize()); DicomDTO dto = ExtractDTO(data); MITK_INFO << mitk::RESTUtil::convertToUtf8(dto.imageSeriesUID); emit InvokeSimilarityGraph(dto.simScoreArray, dto.minSliceStart); emit InvokeUpdateDcmMeta(dto); mitk::RESTUtil::ParamMap seriesInstancesParams; seriesInstancesParams.insert(mitk::RESTUtil::ParamMap::value_type(U("StudyInstanceUID"), dto.studyUID)); seriesInstancesParams.insert(mitk::RESTUtil::ParamMap::value_type(U("SeriesInstanceUID"), dto.srSeriesUID)); seriesInstancesParams.insert( mitk::RESTUtil::ParamMap::value_type(U("includefield"), U("0040A375"))); // Current Requested Procedure Evidence Sequence try { MITK_INFO << "send qido request"; m_DicomWeb.SendQIDO(seriesInstancesParams).then([=](web::json::value jsonResult) { auto firstResult = jsonResult[0]; auto actualListKey = firstResult.at(U("0040A375")) .as_object() .at(U("Value")) .as_array()[0] .as_object() .at(U("00081115")) .as_object() .at(U("Value")) .as_array(); MITK_INFO << "received qido response"; utility::string_t segSeriesUIDA = {}; utility::string_t segSeriesUIDB = {}; utility::string_t imageSeriesUID = {}; for (unsigned int index = 0; index < actualListKey.size(); index++) { auto element = actualListKey[index].as_object(); // get SOP class UID auto innerElement = element.at(U("00081199")).as_object().at(U("Value")).as_array()[0]; auto sopClassUID = innerElement.at(U("00081150")).as_object().at(U("Value")).as_array()[0].as_string(); auto seriesUID = element.at(U("0020000E")).as_object().at(U("Value")).as_array()[0].as_string(); if (sopClassUID == U("1.2.840.10008.5.1.4.1.1.66.4")) // SEG { if (segSeriesUIDA.length() == 0) { segSeriesUIDA = seriesUID; } else { segSeriesUIDB = seriesUID; } } else if (sopClassUID == U("1.2.840.10008.5.1.4.1.1.2")) // CT { imageSeriesUID = seriesUID; } } emit InvokeProgress(10, {"load composite context of structured report"}); MITK_INFO << "image series UID " << mitk::RESTUtil::convertToUtf8(imageSeriesUID); MITK_INFO << "seg A series UID " << mitk::RESTUtil::convertToUtf8(segSeriesUIDA); MITK_INFO << "seg B series UID " << mitk::RESTUtil::convertToUtf8(segSeriesUIDB); MITK_INFO << "Load related dicom series ..."; std::string folderPathSeries = mitk::IOUtil::CreateTemporaryDirectory("XXXXXX", m_DownloadDir) + "/"; std::string pathSegA = mitk::IOUtil::CreateTemporaryDirectory("XXXXXX", m_DownloadDir) + "/"; std::string pathSegB = mitk::IOUtil::CreateTemporaryDirectory("XXXXXX", m_DownloadDir) + "/"; auto folderPathSegA = utility::conversions::to_string_t(pathSegA); auto folderPathSegB = utility::conversions::to_string_t(pathSegB); std::vector> tasks; auto imageSeriesTask = m_DicomWeb.SendWADO(utility::conversions::to_string_t(folderPathSeries), dto.studyUID, imageSeriesUID); auto segATask = m_DicomWeb.SendWADO(folderPathSegA, dto.studyUID, segSeriesUIDA); auto segBTask = m_DicomWeb.SendWADO(folderPathSegB, dto.studyUID, segSeriesUIDB); tasks.push_back(imageSeriesTask); tasks.push_back(segATask); tasks.push_back(segBTask); auto joinTask = pplx::when_all(begin(tasks), end(tasks)); auto filePathList = joinTask.then([&](std::vector filePathList) { emit InvokeProgress(50, {"load dicom files from disk"}); emit InvokeLoadDataSegRework(filePathList); }); }); } catch (mitk::Exception &e) { MITK_ERROR << e.what(); } web::http::http_response response(web::http::status_codes::InternalError); response.set_body(U("Something went wrong while processing the request.")); // TODO: include method name return response; } web::http::http_response ReworkRequestHandler::HandleGet(const web::uri &uri, const web::json::value &data) { if (!data.is_null()) // avoid unused warning MITK_INFO << "data was not null"; auto query = web::uri(uri).query(); auto httpParams = web::uri::split_query(query); // IHE Invoke Image Display style auto requestType = httpParams.find(U("requestType")); auto errorResponse = web::http::http_response(web::http::status_codes::BadRequest); if (requestType != httpParams.end()) { if (requestType->second == U("LOAD_SERIES")) { // data extraction DicomDTO dto; dto.studyUID = httpParams.at(U("studyUID")); auto seriesUIDList = httpParams.at(U("seriesUIDList")); auto seriesUIDListUtf8 = mitk::RESTUtil::convertToUtf8(seriesUIDList); std::istringstream f(seriesUIDListUtf8); std::string s; while (getline(f, s, ',')) { dto.seriesUIDList.push_back(mitk::RESTUtil::convertToTString(s)); } emit InvokeProgress(20, {"incoming series request ..."}); // tasks std::vector> tasks; if (dto.seriesUIDList.size() > 0) { for (auto segSeriesUID : dto.seriesUIDList) { utility::string_t folderPathSeries = utility::conversions::to_string_t(mitk::IOUtil::CreateTemporaryDirectory("XXXXXX", m_DownloadDir) + "/"); try { auto seriesTask = m_DicomWeb.SendWADO(folderPathSeries, dto.studyUID, segSeriesUID); tasks.push_back(seriesTask); } catch (const mitk::Exception &exception) { MITK_INFO << exception.what(); return errorResponse; } } } emit InvokeProgress(40, {"download series ..."}); try { auto joinTask = pplx::when_all(begin(tasks), end(tasks)); auto filePathList = joinTask.then([&](std::vector filePathList) { emit InvokeLoadData(filePathList); emit InvokeProgress(40, {""}); }); } catch (const mitk::Exception &exception) { MITK_INFO << exception.what(); return errorResponse; } } } else { MITK_INFO << "no requestType parameter was provided"; } return errorResponse; } web::http::http_response ReworkRequestHandler::HandleOptions(const web::uri &uri, const web::json::value &data) { if (uri.to_string() != U("/inject")) // avoid unused warning MITK_INFO << "no inject path"; if (!data.is_null()) // avoid unused warning MITK_INFO << "data was not null"; MITK_INFO << "OPTIONS incoming"; web::http::http_response response(web::http::status_codes::OK); response.headers().add(U("Access-Control-Allow-Methods"), "PUT"); response.headers().add(U("Access-Control-Allow-Headers"), "Content-Type"); response.headers().add(U("Access-Control-Allow-Origin"), "http://localhost:8002"); return response; } \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/ReworkRequestHandler.h b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/ReworkRequestHandler.h index e934786540..0b6233d101 100644 --- a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/ReworkRequestHandler.h +++ b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/ReworkRequestHandler.h @@ -1,79 +1,79 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef ReworkRequestHandler_h #define ReworkRequestHandler_h -#include "DICOMweb.h" +#include #include #include #include /** * @brief This class represents the http message handler for the segmentation rework. * @author Tobias Stein */ class ReworkRequestHandler : public QObject, public mitk::IRESTObserver { Q_OBJECT public: struct DicomDTO { utility::string_t segSeriesUIDA; utility::string_t segSeriesUIDB; utility::string_t imageSeriesUID; utility::string_t studyUID; utility::string_t segInstanceUIDA; utility::string_t segInstanceUIDB; utility::string_t srSeriesUID; std::vector seriesUIDList; std::vector simScoreArray; int minSliceStart; utility::string_t groundTruth; }; ReworkRequestHandler(); /** * Creates the request handler for segmentation rework. The received data is stored into the given download dir. * * @param downloadDir the directory to which received data is stored. */ ReworkRequestHandler(std::string downloadDir, utility::string_t pacsURI); /** * Overrides IRESTObserver::Notify. Here arrive the incoming messages. */ web::http::http_response Notify(const web::uri &uri, const web::json::value &data, const web::http::method &method); signals: void InvokeProgress(int, QString status); void InvokeSimilarityGraph(std::vector score, int sliceStart); void InvokeUpdateDcmMeta(DicomDTO dto); void InvokeLoadData(std::vector); void InvokeLoadDataSegRework(std::vector); private: DicomDTO ExtractDTO(const web::json::value &data); web::http::http_response HandlePut(const web::uri &uri, const web::json::value &data); web::http::http_response HandleGet(const web::uri &uri, const web::json::value &data); web::http::http_response HandleOptions(const web::uri &uri, const web::json::value &data); std::string m_DownloadDir; - DICOMweb m_DicomWeb; + mitk::DICOMweb m_DicomWeb; }; #endif // ReworkRequestHandler_h diff --git a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkView.cpp b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkView.cpp index 98365cfa48..52c1fa4645 100644 --- a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkView.cpp @@ -1,537 +1,537 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "SegmentationReworkView.h" #include #include // Qt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include "DICOMweb.h" +#include #include #include const std::string SegmentationReworkView::VIEW_ID = "org.mitk.views.segmentationreworkview"; void SegmentationReworkView::SetFocus() {} void SegmentationReworkView::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; qRegisterMetaType>("std::vector"); qRegisterMetaType>("std::vector"); qRegisterMetaType("DicomDTO"); m_Controls.cleanDicomBtn->setVisible(true); m_Controls.individualWidget_2->setVisible(false); m_Controls.sliderWidget->setMinimum(1); m_Controls.sliderWidget->setMaximum(100); m_Controls.sliderWidget->setTickInterval(1); m_Controls.sliderWidget->setSingleStep(1); m_Controls.radioA->setChecked(true); connect(m_Controls.buttonUpload, &QPushButton::clicked, this, &SegmentationReworkView::UploadNewSegmentation); connect(m_Controls.buttonNewSeg, &QPushButton::clicked, this, &SegmentationReworkView::CreateNewSegmentationC); connect(m_Controls.cleanDicomBtn, &QPushButton::clicked, this, &SegmentationReworkView::CleanDicomFolder); connect(m_Controls.restartConnection, &QPushButton::clicked, this, &SegmentationReworkView::OnRestartConnection); connect(m_Controls.testConnection, &QPushButton::clicked, this, &SegmentationReworkView::TestConnection); connect(m_Controls.checkIndiv, &QCheckBox::stateChanged, this, &SegmentationReworkView::OnIndividualCheckChange); connect( m_Controls.sliderWidget, &ctkSliderWidget::valueChanged, this, &SegmentationReworkView::OnSliderWidgetChanged); m_DownloadBaseDir = mitk::IOUtil::GetTempPath() + "segrework"; MITK_INFO << "using download base dir: " << m_DownloadBaseDir; m_UploadBaseDir = mitk::IOUtil::GetTempPath() + "uploadSeg"; if (!itksys::SystemTools::FileIsDirectory(m_DownloadBaseDir)) { itk::FileTools::CreateDirectory(m_DownloadBaseDir); } if (!itksys::SystemTools::FileIsDirectory(m_UploadBaseDir)) { itk::FileTools::CreateDirectory(m_UploadBaseDir); } utility::string_t path = U("/inject"); utility::string_t port = U("4040"); utility::string_t address = U("http://localhost:"); address.append(port); address.append(path); m_Host = "http://localhost:8000/rest-srs"; utility::string_t pacsURL = U("http://193.174.48.78:8090"); m_RequestHandler = new ReworkRequestHandler(m_DownloadBaseDir, pacsURL); connect(this, &SegmentationReworkView::InvokeProgress, this, &SegmentationReworkView::AddProgress); connect(m_RequestHandler, &ReworkRequestHandler::InvokeProgress, this, &SegmentationReworkView::AddProgress); connect( m_RequestHandler, &ReworkRequestHandler::InvokeSimilarityGraph, this, &SegmentationReworkView::SetSimilarityGraph); connect( m_RequestHandler, &ReworkRequestHandler::InvokeUpdateDcmMeta, this, &SegmentationReworkView::InitializeDcmMeta); connect(m_RequestHandler, &ReworkRequestHandler::InvokeLoadData, this, &SegmentationReworkView::LoadData); connect( m_RequestHandler, &ReworkRequestHandler::InvokeLoadDataSegRework, this, &SegmentationReworkView::LoadDataSegRework); // Get the micro service us::ModuleContext *context = us::ModuleRegistry::GetModule(1)->GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { m_ManagerService = managerService; } } // Setup PACS connection RestartConnection(pacsURL); // Setup listening server m_ManagerService->ReceiveRequest(address, m_RequestHandler); MITK_INFO << "Listening for requests at: " << utility::conversions::to_utf8string(address); } void SegmentationReworkView::OnSliderWidgetChanged(double value) { std::map::iterator it; unsigned int count = 0; for (it = m_ScoreMap.begin(); it != m_ScoreMap.end(); it++) { if (it->second < value) { count++; } } QString labelsToDelete = "slices to delete: " + QString::number(count); m_Controls.slicesToDeleteLabel->setText(labelsToDelete); std::map thresholdMap; for (it = m_ScoreMap.begin(); it != m_ScoreMap.end(); it++) { thresholdMap.insert(std::map::value_type(it->first, value)); } m_Controls.chartWidget->RemoveData(m_thresholdLabel); m_Controls.chartWidget->AddData2D(thresholdMap, m_thresholdLabel); m_Controls.chartWidget->SetChartType(m_thresholdLabel, QmitkChartWidget::ChartType::line); m_Controls.chartWidget->Show(); } void SegmentationReworkView::AddProgress(int progress, QString status) { auto futureValue = m_Controls.progressBar->value() + progress; if (futureValue >= 100) { m_Controls.progressBar->setValue(0); m_Controls.progressBar->setFormat(""); } else { m_Controls.progressBar->setFormat(status.append(" %p%")); m_Controls.progressBar->setValue(futureValue); } } void SegmentationReworkView::InitializeDcmMeta(ReworkRequestHandler::DicomDTO dto) { m_CurrentStudyUID = mitk::RESTUtil::convertToUtf8(dto.studyUID); m_SRUID = mitk::RESTUtil::convertToUtf8(dto.srSeriesUID); m_GroundTruth = mitk::RESTUtil::convertToUtf8(dto.groundTruth); } pplx::task SegmentationReworkView::TestConnection() { mitk::RESTUtil::ParamMap seriesInstancesParams; seriesInstancesParams.insert(mitk::RESTUtil::ParamMap::value_type(U("limit"), U("1"))); m_Controls.connectionStatus->setText(QString("Testing connection ...")); return m_DicomWeb.SendQIDO(seriesInstancesParams).then([=](pplx::task resultTask) { try { auto result = resultTask.get(); if (!result.is_null()) { m_Controls.connectionStatus->setText(QString("Connection works!")); return true; } else { m_Controls.connectionStatus->setText(QString("Trouble with connection. Not valid!")); return false; } } catch (mitk::Exception &e) { MITK_WARN << e.what(); m_Controls.connectionStatus->setText(QString("No connection possible.")); return false; } }); } void SegmentationReworkView::OnRestartConnection() { RestartConnection(mitk::RESTUtil::convertToTString(m_Controls.dcm4cheeHostValue->text().toStdString())); } void SegmentationReworkView::RestartConnection(utility::string_t newHost) { utility::string_t host; if (newHost.empty()) { MITK_INFO << "Host was empty"; m_Controls.connectionStatus->setText(QString("Host must not be empty!")); return; } utility::string_t url = newHost + U("/dcm4chee-arc/aets/DCM4CHEE/"); MITK_INFO << "Restarting connection to " << mitk::RESTUtil::convertToUtf8(url) << " ..."; m_Controls.connectionStatus->setText(QString("Restarting connection...")); m_Controls.dcm4cheeURL->setText({(utility::conversions::to_utf8string(url).c_str())}); - m_DicomWeb = DICOMweb(url); + m_DicomWeb = mitk::DICOMweb(url); if (!TestConnection().get()) { MITK_INFO << "Restart did not work.."; m_Controls.connectionStatus->setText(QString("No PACS server available under given host!")); } else { MITK_INFO << "requests to pacs are sent to: " << mitk::RESTUtil::convertToUtf8(url); } } void SegmentationReworkView::OnIndividualCheckChange(int state) { if (state == Qt::Unchecked) { m_Controls.individualWidget_2->setVisible(false); } else if (state == Qt::Checked) { m_Controls.individualWidget_2->setVisible(true); } } std::string SegmentationReworkView::GetAlgorithmOfSegByPath(std::string path) { auto scanner = mitk::DICOMDCMTKTagScanner::New(); mitk::DICOMTagPath algorithmName; algorithmName.AddAnySelection(0x0062, 0x0002).AddElement(0x0062, 0x0009); mitk::StringList files; files.push_back(path); scanner->SetInputFiles(files); scanner->AddTagPath(algorithmName); scanner->Scan(); mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList(); auto findings = frames.front()->GetTagValueAsString(algorithmName); if (findings.size() != 0) MITK_INFO << findings.front().value; return findings.front().value; } mitk::DataStorage::SetOfObjects::Pointer SegmentationReworkView::LoadData(std::vector filePathList) { MITK_INFO << "Pushing data to data storage ..."; auto ds = GetDataStorage(); auto dataNodes = mitk::IOUtil::Load(filePathList, *ds); // reinit view mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(ds); return dataNodes; } void SegmentationReworkView::LoadDataSegRework(std::vector filePathList) { auto dataNodes = LoadData(filePathList); // find data nodes m_Image = dataNodes->at(0); m_Image->SetName("image data"); m_SegA = dataNodes->at(1); m_SegB = dataNodes->at(2); auto algorithmNameA = GetAlgorithmOfSegByPath(filePathList[1]); auto algorithmNameB = GetAlgorithmOfSegByPath(filePathList[2]); m_SegA->SetName(algorithmNameA); m_SegB->SetName(algorithmNameB); m_Controls.labelSegAValue->setText(algorithmNameA.c_str()); m_Controls.labelSegBValue->setText(algorithmNameB.c_str()); m_Controls.labelGroundTruthValue->setText(m_GroundTruth.c_str()); emit InvokeProgress(20, {""}); } void SegmentationReworkView::SetSimilarityGraph(std::vector simScoreArray, int sliceMinStart) { std::string label = "similarity graph"; m_thresholdLabel = "threshold"; double sliceIndex = sliceMinStart; for (double score : simScoreArray) { m_ScoreMap.insert(std::map::value_type(sliceIndex, score)); sliceIndex++; } std::map thresholdMap; m_Controls.chartWidget->AddData2D(m_ScoreMap, label); m_Controls.chartWidget->AddData2D(thresholdMap, m_thresholdLabel); m_Controls.chartWidget->SetChartType(label, QmitkChartWidget::ChartType::line); m_Controls.chartWidget->SetChartType(m_thresholdLabel, QmitkChartWidget::ChartType::line); m_Controls.chartWidget->SetXAxisLabel("slice number"); m_Controls.chartWidget->SetYAxisLabel("similarity in percent"); m_Controls.chartWidget->SetTitle("Similartiy Score for Segmentation Comparison"); m_Controls.chartWidget->Show(); } void SegmentationReworkView::UploadNewSegmentation() { AddProgress(10, {"save SEG to temp folder"}); std::string folderPathSeg = mitk::IOUtil::CreateTemporaryDirectory("XXXXXX", m_UploadBaseDir) + "/"; const std::string savePath = folderPathSeg + m_SegC->GetName() + ".dcm"; const std::string mimeType = mitk::MitkDICOMQIIOMimeTypes::DICOMSEG_MIMETYPE_NAME(); mitk::IOUtil::Save(m_SegC->GetData(), mimeType, savePath); // get Series Instance UID from new SEG auto scanner = mitk::DICOMDCMTKTagScanner::New(); mitk::DICOMTagPath seriesUID(0x0020, 0x000E); mitk::StringList files; files.push_back(savePath); scanner->SetInputFiles(files); scanner->AddTagPath(seriesUID); scanner->Scan(); mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList(); auto findings = frames.front()->GetTagValueAsString(seriesUID); auto segSeriesUID = findings.front().value; AddProgress(20, {"push SEG to PACS"}); auto filePath = utility::conversions::to_string_t(savePath); try { m_DicomWeb.SendSTOW(filePath, mitk::RESTUtil::convertToTString(m_CurrentStudyUID)).then([=] { emit InvokeProgress(50, {"persist reworked SEG to evaluation database"}); - DICOMweb::MitkUriBuilder queryBuilder(mitk::RESTUtil::convertToTString(m_Host) + U("/tasks/evaluations/")); + mitk::DICOMweb::MitkUriBuilder queryBuilder(mitk::RESTUtil::convertToTString(m_Host) + U("/tasks/evaluations/")); queryBuilder.append_query(U("srUID"), utility::conversions::to_string_t(m_SRUID)); auto content = web::json::value(); m_ManagerService->SendRequest(queryBuilder.to_uri(), mitk::IRESTManager::RequestType::Get, &content) .then([=](web::json::value result) { MITK_INFO << "after GET"; MITK_INFO << utility::conversions::to_utf8string(result.serialize()); auto updatedContent = result.as_array()[0]; updatedContent[U("reworkedSegmentationUID")] = web::json::value::string(utility::conversions::to_string_t(segSeriesUID)); auto id = updatedContent.at(U("id")).as_integer(); MITK_INFO << id; auto idParam = std::to_string(id).append("/"); - DICOMweb::MitkUriBuilder queryBuilder(mitk::RESTUtil::convertToTString(m_Host) + U("/tasks/evaluations")); + mitk::DICOMweb::MitkUriBuilder queryBuilder(mitk::RESTUtil::convertToTString(m_Host) + U("/tasks/evaluations")); queryBuilder.append_path(utility::conversions::to_string_t(idParam)); m_ManagerService->SendRequest(queryBuilder.to_uri(), mitk::IRESTManager::RequestType::Put, &updatedContent) .then([=](web::json::value result) { MITK_INFO << utility::conversions::to_utf8string(result.serialize()); if (result[U("reworkedSegmentationUID")].as_string() == utility::conversions::to_string_t(segSeriesUID)) { MITK_INFO << "successfully stored"; emit InvokeProgress(30, {"successfully stored"}); } }); }); }); } catch (const std::exception &exception) { std::cout << exception.what() << std::endl; } } std::vector SegmentationReworkView::CreateSegmentation(mitk::Image::Pointer baseSegmentation, double threshold) { MITK_INFO << "handle individual segmentation creation"; std::map::iterator it; std::vector sliceIndices; unsigned int count = 0; for (it = m_ScoreMap.begin(); it != m_ScoreMap.end(); it++) { if (it->second < threshold) { auto index = it->first; try { mitk::ImagePixelWriteAccessor imageAccessor(baseSegmentation); for (unsigned int x = 0; x < baseSegmentation->GetDimension(0); x++) { for (unsigned int y = 0; y < baseSegmentation->GetDimension(1); y++) { imageAccessor.SetPixelByIndex({{x, y, int(index)}}, 0); } } } catch (mitk::Exception &e) { MITK_ERROR << e.what(); } count++; sliceIndices.push_back(index); MITK_INFO << "slice " << it->first << " removed "; } } MITK_INFO << "slices deleted " << count; return sliceIndices; } void SegmentationReworkView::CreateNewSegmentationC() { mitk::ToolManager *toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); toolManager->InitializeTools(); toolManager->SetReferenceData(m_Image); mitk::Image::Pointer baseImage; if (m_Controls.radioA->isChecked()) { baseImage = dynamic_cast(m_SegA->GetData())->Clone(); } else if (m_Controls.radioB->isChecked()) { baseImage = dynamic_cast(m_SegB->GetData())->Clone(); } if (m_Controls.checkIndiv->isChecked()) { auto sliceIndices = CreateSegmentation(baseImage, m_Controls.sliderWidget->value()); } QmitkNewSegmentationDialog *dialog = new QmitkNewSegmentationDialog(m_Parent); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) { // user clicked cancel or pressed Esc or something similar return; } // ask the user about an organ type and name, add this information to the image's (!) propertylist // create a new image of the same dimensions and smallest possible pixel type mitk::Tool *firstTool = toolManager->GetToolById(0); if (firstTool) { try { std::string newNodeName = dialog->GetSegmentationName().toStdString(); if (newNodeName.empty()) { newNodeName = "no_name"; } mitk::DataNode::Pointer newSegmentation = firstTool->CreateSegmentationNode(baseImage, newNodeName, dialog->GetColor()); // initialize showVolume to false to prevent recalculating the volume while working on the segmentation newSegmentation->SetProperty("showVolume", mitk::BoolProperty::New(false)); if (!newSegmentation) { return; // could be aborted by user } if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)) { mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)->SetSelected(false); } newSegmentation->SetSelected(true); this->GetDataStorage()->Add( newSegmentation, toolManager->GetReferenceData(0)); // add as a child, because the segmentation "derives" from the original m_SegC = newSegmentation; auto referencedImages = m_Image->GetData()->GetProperty("files"); m_SegC->GetData()->SetProperty("referenceFiles", referencedImages); } catch (std::bad_alloc) { QMessageBox::warning( nullptr, tr("Create new segmentation"), tr("Could not allocate memory for new segmentation")); } } else { MITK_INFO << "no tools..."; } } void SegmentationReworkView::CleanDicomFolder() { if (m_SegA || m_SegB || m_SegC) { QMessageBox::warning(nullptr, tr("Clean dicom folder"), tr("Please remove the data in data storage before cleaning the download folder")); return; } auto downloadDir = Poco::File(m_DownloadBaseDir); downloadDir.remove(true); } diff --git a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkView.h b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkView.h index 53a0e5cd26..51e570c457 100644 --- a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkView.h +++ b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkView.h @@ -1,140 +1,140 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef SegmentationReworkView_h #define SegmentationReworkView_h #include #include #include "ui_SegmentationReworkViewControls.h" #include "ReworkRequestHandler.h" #include #include #include /** @brief SegmentationReworkView This class represents the view to make connections to a PACS server and show some information to do a manual rework upon two existing segmentation volumes. @author Tobias Stein \sa QmitkAbstractView \ingroup ${plugin_target}_internal */ class SegmentationReworkView : public QmitkAbstractView { Q_OBJECT public: static const std::string VIEW_ID; /** * @brief Loads the files given by a list of file paths. * * @param filePathList a list of absolute file paths * @return set of objects containing the newly loaded data nodes */ mitk::DataStorage::SetOfObjects::Pointer LoadData(std::vector filePathList); /** * @brief Loads the files given by a list of file paths. This method expects exactly three items in the list (image * series, seg series a, seg series b). Additional information for segmentation rework is displayed. * * * @param filePathList a list of absolute file paths */ void LoadDataSegRework(std::vector filePathList); /** * @brief Calculates how many slices would be delete if the given threshold would be applied to the segmentation * volume. The information about the segmentation similarity is used and slices below the threshold are to be * discarded. Updates the display. * * @param value the threshold value (between 0 and 1). */ void OnSliderWidgetChanged(double value); /** * @brief Progress is added to the progressbar in a percent value and the given status is displayed. The progress will * not exceed 100 points. * * @param progress the progress in percent points to be added to the bar * @param status the status to be displayed after achieving the progress */ void AddProgress(int progress, QString status); /** * @brief Initializes the DICOM meta data used by this view. * * @param dto the data transfer object for received DICOM meta data. */ void InitializeDcmMeta(ReworkRequestHandler::DicomDTO dto); signals: void InvokeProgress(int, QString status); protected: virtual void CreateQtPartControl(QWidget *parent) override; virtual void SetFocus() override; void CreateNewSegmentationC(); void CleanDicomFolder(); void UploadNewSegmentation(); void RestartConnection(utility::string_t newHost); void OnRestartConnection(); pplx::task TestConnection(); void OnIndividualCheckChange(int state); Ui::SegmentationReworkViewControls m_Controls; private: std::vector CreateSegmentation(mitk::Image::Pointer baseSegmentation, double threshold); std::string GetAlgorithmOfSegByPath(std::string path); void SetSimilarityGraph(std::vector simScoreArray, int sliceMinStart); mitk::IRESTManager *m_ManagerService; ReworkRequestHandler *m_RequestHandler; std::string m_CurrentStudyUID; std::string m_SRUID; std::string m_DownloadBaseDir; std::string m_UploadBaseDir; mitk::DataNode::Pointer m_Image; mitk::DataNode::Pointer m_SegA; mitk::DataNode::Pointer m_SegB; mitk::DataNode::Pointer m_SegC; std::map m_ScoreMap; std::string m_GroundTruth; std::string m_thresholdLabel; - DICOMweb m_DicomWeb; + mitk::DICOMweb m_DicomWeb; QWidget *m_Parent; std::string m_Host; }; #endif // SegmentationReworkView_h