diff --git a/Modules/REST/test/mitkRESTServerTest.cpp b/Modules/REST/test/mitkRESTServerTest.cpp index f5bd3a7f8b..5f620ddc7a 100644 --- a/Modules/REST/test/mitkRESTServerTest.cpp +++ b/Modules/REST/test/mitkRESTServerTest.cpp @@ -1,227 +1,227 @@ /*=================================================================== 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. ===================================================================*/ #ifdef _WIN32 #include #endif #include #include #include #include #include #include #include #include #include class mitkRESTServerTestSuite : public mitk::TestFixture, mitk::IRESTObserver { CPPUNIT_TEST_SUITE(mitkRESTServerTestSuite); MITK_TEST(OpenListener_Succeed); MITK_TEST(TwoListenerSameHostSamePort_OnlyOneOpened); MITK_TEST(CloseListener_Succeed); MITK_TEST(OpenMultipleListenerCloseOne_Succeed); MITK_TEST(OpenMultipleListenerCloseAll_Succeed); // MITK_TEST(OpenListenerGetRequestSamePath_ReturnExpectedJSON); GET requests do not support content yet? MITK_TEST(CloseListener_NoRequestPossible); MITK_TEST(OpenListenerGetRequestDifferentPath_ReturnNotFound); MITK_TEST(OpenListenerCloseAndReopen_Succeed); CPPUNIT_TEST_SUITE_END(); public: mitk::IRESTManager *m_Service; web::json::value m_Data; web::json::value Notify(const web::uri &, const web::json::value &, const web::http::method &) override { return m_Data; } /** * @brief Setup Always call this method before each Test-case to ensure correct and new intialization of the used * members for a new test case. (If the members are not used in a test, the method does not need to be called). */ void setUp() override { m_Data = web::json::value(); m_Data[U("userId")] = web::json::value(1); m_Data[U("id")] = web::json::value(1); m_Data[U("title")] = web::json::value(U("this is a title")); m_Data[U("body")] = web::json::value(U("this is a body")); auto serviceRef = us::GetModuleContext()->GetServiceReference(); if (serviceRef) m_Service = us::GetModuleContext()->GetService(serviceRef); if (!m_Service) CPPUNIT_FAIL("Getting Service in setUp() failed"); } void tearDown() override { m_Service->HandleDeleteObserver(this); } void OpenListener_Succeed() { m_Service->ReceiveRequest(U("http://localhost:8080/servertest"), this); CPPUNIT_ASSERT_MESSAGE("Open one listener, observer map size is one", 1 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Open one listener, server map size is one", 1 == m_Service->GetServerMap().size()); } void TwoListenerSameHostSamePort_OnlyOneOpened() { m_Service->ReceiveRequest(U("http://localhost:8080/servertest"), this); m_Service->ReceiveRequest(U("http://localhost:8080/serverexample"), this); CPPUNIT_ASSERT_MESSAGE("Open two listener with a different path,same host, same port, observer map size is two", 2 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Open two listener with a different path,same host, same port, server map size is one", 1 == m_Service->GetServerMap().size()); } void CloseListener_Succeed() { m_Service->ReceiveRequest(U("http://localhost:8080/servertest"), this); CPPUNIT_ASSERT_MESSAGE("Open one listener, observer map size is one", 1 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Open one listener, server map size is one", 1 == m_Service->GetServerMap().size()); m_Service->HandleDeleteObserver(this); CPPUNIT_ASSERT_MESSAGE("Closed listener, observer map is empty", 0 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Closed listener, server map is empty", 0 == m_Service->GetServerMap().size()); } void OpenMultipleListenerCloseOne_Succeed() { m_Service->ReceiveRequest(U("http://localhost:8080/servertest"), this); m_Service->ReceiveRequest(U("http://localhost:8090/serverexample"), this); CPPUNIT_ASSERT_MESSAGE("Open two listener, observer map size is two", 2 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Open two listener, server map size is two", 2 == m_Service->GetServerMap().size()); m_Service->HandleDeleteObserver(this, U("http://localhost:8080/servertest")); CPPUNIT_ASSERT_MESSAGE("Closed one of two listeners, observer map is size is one", 1 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Closed one of two listener, server map size is one", 1 == m_Service->GetServerMap().size()); } void OpenMultipleListenerCloseAll_Succeed() { m_Service->ReceiveRequest(U("http://localhost:8080/servertest"), this); m_Service->ReceiveRequest(U("http://localhost:8090/serverexample"), this); CPPUNIT_ASSERT_MESSAGE("Open two listener, observer map size is two", 2 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Open two listener, server map size is two", 2 == m_Service->GetServerMap().size()); m_Service->HandleDeleteObserver(this); CPPUNIT_ASSERT_MESSAGE("Closed all listeners, observer map is empty", 0 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Closed all listeners, server map is empty", 0 == m_Service->GetServerMap().size()); } void OpenListenerGetRequestSamePath_ReturnExpectedJSON() { m_Service->ReceiveRequest(U("http://localhost:8080/servertest"), this); web::json::value result; - - m_Service->SendRequest(U("http://localhost:8080/servertest")) + auto body = web::json::value(); + m_Service->SendRequest(U("http://localhost:8080/servertest"), mitk::IRESTManager::RequestType::Get, &body) .then([&](pplx::task resultTask) { try { result = resultTask.get(); } catch (const mitk::Exception &exception) { MITK_ERROR << exception.what(); return; } }) .wait(); CPPUNIT_ASSERT_MESSAGE("Opened listener and send request to same uri, returned expected JSON", result == m_Data); } void RequestToClosedListener() { web::json::value result; m_Service->SendRequest(U("http://localhost:8080/servertest")) .then([&](pplx::task resultTask) { result = resultTask.get(); }) .wait(); } void CloseListener_NoRequestPossible() { m_Service->ReceiveRequest(U("http://localhost:8080/servertest"), this); CPPUNIT_ASSERT_MESSAGE("Open one listener, observer map size is one", 1 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Open one listener, server map size is one", 1 == m_Service->GetServerMap().size()); m_Service->HandleDeleteObserver(this); CPPUNIT_ASSERT_MESSAGE("Closed listener, observer map is empty", 0 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Closed listener, server map is empty", 0 == m_Service->GetServerMap().size()); CPPUNIT_ASSERT_THROW(RequestToClosedListener(), mitk::Exception); } void RequestToDifferentPathNotFound() { m_Service->ReceiveRequest(U("http://localhost:8080/servertest"), this); web::json::value result; m_Service->SendRequest(U("http://localhost:8080/serverexample")) .then([&](pplx::task resultTask) { result = resultTask.get(); }) .wait(); } void OpenListenerGetRequestDifferentPath_ReturnNotFound() { CPPUNIT_ASSERT_THROW(RequestToDifferentPathNotFound(), mitk::Exception); } void OpenListenerCloseAndReopen_Succeed() { m_Service->ReceiveRequest(U("http://localhost:8080/servertest"), this); CPPUNIT_ASSERT_MESSAGE("Open one listener, observer map size is one", 1 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Open one listener, server map size is one", 1 == m_Service->GetServerMap().size()); m_Service->HandleDeleteObserver(this); CPPUNIT_ASSERT_MESSAGE("Closed listener, observer map is empty", 0 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Closed listener, server map is empty", 0 == m_Service->GetServerMap().size()); m_Service->ReceiveRequest(U("http://localhost:8080/servertest"), this); CPPUNIT_ASSERT_MESSAGE("Reopened listener, observer map size is one", 1 == m_Service->GetObservers().size()); CPPUNIT_ASSERT_MESSAGE("Reopened listener, server map size is one", 1 == m_Service->GetServerMap().size()); } }; MITK_TEST_SUITE_REGISTRATION(mitkRESTServer) diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 73ca842a78..2bc57baa4a 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,116 +1,117 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:ON org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF #org.blueberry.test:ON #org.blueberry.uitest:ON #Testing/org.blueberry.core.runtime.tests:ON #Testing/org.blueberry.osgi.tests:ON org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.chartExample:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF org.mitk.gui.qt.datastorageviewertest:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.diffusionimaging.connectomics:OFF org.mitk.gui.qt.diffusionimaging.denoising:OFF org.mitk.gui.qt.diffusionimaging.fiberfox:OFF org.mitk.gui.qt.diffusionimaging.fiberprocessing:OFF org.mitk.gui.qt.diffusionimaging.ivim:OFF org.mitk.gui.qt.diffusionimaging.odfpeaks:OFF org.mitk.gui.qt.diffusionimaging.partialvolume:OFF org.mitk.gui.qt.diffusionimaging.preprocessing:OFF org.mitk.gui.qt.diffusionimaging.reconstruction:OFF org.mitk.gui.qt.diffusionimaging.registration:OFF org.mitk.gui.qt.diffusionimaging.tractography:OFF org.mitk.gui.qt.diffusionimaging.python:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.lasercontrol:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.segmentation.rework:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.renderwindowmanager:OFF org.mitk.gui.qt.semanticrelations:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.photoacoustics.pausviewer:OFF org.mitk.gui.qt.photoacoustics.pausmotioncompensation:OFF org.mitk.gui.qt.photoacoustics.imageprocessing:OFF org.mitk.gui.qt.photoacoustics.simulation:OFF org.mitk.gui.qt.photoacoustics.spectralunmixing:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.echotrack:OFF org.mitk.gui.qt.spectrocamrecorder:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.igt.app.hummelprotocolmeasurements:OFF org.mitk.gui.qt.multilabelsegmentation:OFF org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.algorithm.batch:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF org.mitk.gui.qt.matchpoint.evaluator:OFF org.mitk.gui.qt.matchpoint.manipulator:OFF org.mitk.gui.qt.preprocessing.resampling:OFF org.mitk.gui.qt.radiomics:OFF org.mitk.gui.qt.cest:OFF org.mitk.gui.qt.fit.demo:OFF org.mitk.gui.qt.fit.inspector:OFF org.mitk.gui.qt.fit.genericfitting:OFF org.mitk.gui.qt.pharmacokinetics.mri:OFF org.mitk.gui.qt.pharmacokinetics.pet:OFF org.mitk.gui.qt.pharmacokinetics.simulation:OFF org.mitk.gui.qt.pharmacokinetics.curvedescriptor:OFF - org.mitk.gui.qt.pharmacokinetics.concentration.mri:OFF + org.mitk.gui.qt.pharmacokinetics.concentration.mri:OFF org.mitk.gui.qt.inject:OFF + ) diff --git a/Plugins/org.mitk.gui.qt.inject/CMakeLists.txt b/Plugins/org.mitk.gui.qt.inject/CMakeLists.txt new file mode 100644 index 0000000000..22749962e8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/CMakeLists.txt @@ -0,0 +1,8 @@ +project(org_mitk_gui_qt_inject) + +mitk_create_plugin( + EXPORT_DIRECTIVE INJECT_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgetsExt MitkREST MitkRESTService MitkDICOMweb MitkChart MitkSegmentationUI + PACKAGE_DEPENDS PUBLIC CTK|CTKWidgets +) diff --git a/Plugins/org.mitk.gui.qt.inject/files.cmake b/Plugins/org.mitk.gui.qt.inject/files.cmake new file mode 100644 index 0000000000..b3b3de3564 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/files.cmake @@ -0,0 +1,46 @@ +set(SRC_CPP_FILES + +) + +set(INTERNAL_CPP_FILES + org_mitk_gui_qt_inject_Activator.cpp + InjectView.cpp + InjectRequestHandler.cpp +) + +set(UI_FILES + src/internal/InjectViewControls.ui +) + +set(MOC_H_FILES + src/internal/org_mitk_gui_qt_inject_Activator.h + src/internal/InjectView.h + src/internal/InjectRequestHandler.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.inject/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.inject/manifest_headers.cmake new file mode 100644 index 0000000000..7f8f86fcbe --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "Inject") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ") +set(Plugin-ContactAddress "") +set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.inject/plugin.xml b/Plugins/org.mitk.gui.qt.inject/plugin.xml new file mode 100644 index 0000000000..2fee26c466 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/plugin.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.inject/resources/icon.xpm b/Plugins/org.mitk.gui.qt.inject/resources/icon.xpm new file mode 100644 index 0000000000..9057c20bc6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/resources/icon.xpm @@ -0,0 +1,21 @@ +/* XPM */ +static const char * icon_xpm[] = { +"16 16 2 1", +" c #FF0000", +". c #000000", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Plugins/org.mitk.gui.qt.inject/resources/plugin_icon.png b/Plugins/org.mitk.gui.qt.inject/resources/plugin_icon.png new file mode 100644 index 0000000000..9df327c59a Binary files /dev/null and b/Plugins/org.mitk.gui.qt.inject/resources/plugin_icon.png differ diff --git a/Plugins/org.mitk.gui.qt.inject/src/internal/InjectRequestHandler.cpp b/Plugins/org.mitk.gui.qt.inject/src/internal/InjectRequestHandler.cpp new file mode 100644 index 0000000000..3a984c6a66 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/src/internal/InjectRequestHandler.cpp @@ -0,0 +1,149 @@ +/*=================================================================== + +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 "InjectRequestHandler.h" + +#include +#include +#include + +US_INITIALIZE_MODULE + +InjectRequestHandler::InjectRequestHandler() {} + +InjectRequestHandler::InjectRequestHandler(std::string downloadDir, utility::string_t pacsURI) + : m_DownloadDir{downloadDir} +{ + m_DicomWeb = mitk::DICOMweb(pacsURI + U("/dcm4chee-arc/aets/DCM4CHEE/")); +} + + +web::http::http_response InjectRequestHandler::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::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 InjectRequestHandler::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 InjectRequestHandler::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.inject/src/internal/InjectRequestHandler.h b/Plugins/org.mitk.gui.qt.inject/src/internal/InjectRequestHandler.h new file mode 100644 index 0000000000..ce82d7f6e3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/src/internal/InjectRequestHandler.h @@ -0,0 +1,75 @@ +/*=================================================================== + +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 InjectRequestHandler_h +#define InjectRequestHandler_h + +#include +#include +#include +#include + +/** + * @brief This class represents the http message handler for the segmentation Inject. + * @author Tobias Stein + */ +class InjectRequestHandler : 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; + }; + + InjectRequestHandler(); + + /** + * Creates the request handler for segmentation Inject. The received data is stored into the given download dir. + * + * @param downloadDir the directory to which received data is stored. + */ + InjectRequestHandler(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 InvokeUpdateDcmMeta(DicomDTO dto); + void InvokeLoadData(std::vector); + +private: + 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; + mitk::DICOMweb m_DicomWeb; +}; + +#endif // InjectRequestHandler_h diff --git a/Plugins/org.mitk.gui.qt.inject/src/internal/InjectView.cpp b/Plugins/org.mitk.gui.qt.inject/src/internal/InjectView.cpp new file mode 100644 index 0000000000..d3568aa3c1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/src/internal/InjectView.cpp @@ -0,0 +1,279 @@ +/*=================================================================== + +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 "InjectView.h" + +#include +#include + +// Qt +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +const std::string InjectView::VIEW_ID = "org.mitk.views.injectview"; + +void InjectView::SetFocus() {} + +void InjectView::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); + + connect(m_Controls.cleanDicomBtn, &QPushButton::clicked, this, &InjectView::CleanDicomFolder); + connect(m_Controls.restartConnection, &QPushButton::clicked, this, &InjectView::OnRestartConnection); + connect(m_Controls.testConnection, &QPushButton::clicked, this, &InjectView::TestConnection); + + m_DownloadBaseDir = mitk::IOUtil::GetTempPath() + "segInject"; + 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); + } + + m_HostURL = U("http://localhost"); + + auto host = m_HostURL; + auto envHostURL = std::getenv("HOST_URL"); + + if (envHostURL) + { + host = mitk::RESTUtil::convertToTString(std::string(envHostURL)); + } + + m_restURL = host.append(U("/rest-srs")); + + utility::string_t pacsURL = U("http://193.174.48.78:8090"); + auto envPacsURL = std::getenv("PACS_URL"); + + if (envPacsURL) + { + pacsURL = mitk::RESTUtil::convertToTString(std::string(envPacsURL)); + } + + + m_RequestHandler = new InjectRequestHandler(m_DownloadBaseDir, pacsURL); + + connect(this, &InjectView::InvokeProgress, this, &InjectView::AddProgress); + connect(m_RequestHandler, &InjectRequestHandler::InvokeProgress, this, &InjectView::AddProgress); + connect( + m_RequestHandler, &InjectRequestHandler::InvokeUpdateDcmMeta, this, &InjectView::InitializeDcmMeta); + connect(m_RequestHandler, &InjectRequestHandler::InvokeLoadData, this, &InjectView::LoadData); + + // 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); +} + +void InjectView::Activated() +{ + MITK_INFO << "activated"; + StartServer(); +} + +void InjectView::Deactivated() +{ + MITK_INFO << "deactivated"; + m_ManagerService->HandleDeleteObserver(m_RequestHandler); +} + +void InjectView::Visible() +{ +} + +void InjectView::Hidden() +{ +} + +void InjectView::StartServer() +{ + utility::string_t path = U("/inject"); + + auto pathEnv = std::getenv("SERVER_PATH"); + if (pathEnv) + { + path = mitk::RESTUtil::convertToTString(std::string(pathEnv)); + } + + utility::string_t port = U(":4040"); + utility::string_t address = m_HostURL; + address.append(port); + address.append(path); + // Setup listening server + m_ManagerService->ReceiveRequest(address, m_RequestHandler); + MITK_INFO << "Listening for requests at: " << utility::conversions::to_utf8string(address); +} + +void InjectView::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 InjectView::InitializeDcmMeta(InjectRequestHandler::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 InjectView::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 InjectView::OnRestartConnection() +{ + RestartConnection(mitk::RESTUtil::convertToTString(m_Controls.dcm4cheeHostValue->text().toStdString())); +} + +void InjectView::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 = 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); + } +} + + +mitk::DataStorage::SetOfObjects::Pointer InjectView::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 InjectView::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.inject/src/internal/InjectView.h similarity index 60% copy from Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkView.h copy to Plugins/org.mitk.gui.qt.inject/src/internal/InjectView.h index b31f8c4ff0..c2779bbd0f 100644 --- a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkView.h +++ b/Plugins/org.mitk.gui.qt.inject/src/internal/InjectView.h @@ -1,140 +1,121 @@ /*=================================================================== 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 +#ifndef InjectView_h +#define InjectView_h #include #include -#include "ui_SegmentationReworkViewControls.h" +#include "ui_InjectViewControls.h" -#include "ReworkRequestHandler.h" +#include "InjectRequestHandler.h" #include #include -#include +#include /** - @brief SegmentationReworkView + @brief InjectView - This class represents the view to make connections to a PACS server and show some information to do a manual rework + This class represents the view to make connections to a PACS server and show some information to do a manual Inject upon two existing segmentation volumes. @author Tobias Stein \sa QmitkAbstractView \ingroup ${plugin_target}_internal */ -class SegmentationReworkView : public QmitkAbstractView +class InjectView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { 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); + void InitializeDcmMeta(InjectRequestHandler::DicomDTO dto); + + virtual void Activated() override; + virtual void Deactivated() override; + virtual void Visible() override; + virtual void Hidden() override; 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; + Ui::InjectViewControls 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); + void StartServer(); mitk::IRESTManager *m_ManagerService; - ReworkRequestHandler *m_RequestHandler; + InjectRequestHandler *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; mitk::DICOMweb m_DicomWeb; QWidget *m_Parent; utility::string_t m_restURL; + utility::string_t m_HostURL; }; -#endif // SegmentationReworkView_h +#endif // InjectView_h diff --git a/Plugins/org.mitk.gui.qt.inject/src/internal/InjectViewControls.ui b/Plugins/org.mitk.gui.qt.inject/src/internal/InjectViewControls.ui new file mode 100644 index 0000000000..a4f5abffe4 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/src/internal/InjectViewControls.ui @@ -0,0 +1,126 @@ + + + InjectViewControls + + + + 0 + 0 + 465 + 868 + + + + + 0 + 0 + + + + QmitkTemplate + + + + + + + + dcm4chee host + + + + + + + example input: http://193.174.48.78:8090 + + + + + + + 0 + + + Qt::AlignCenter + + + true + + + + + + + + + restart connection + + + + + + + + + + + + + + + + + + + + + Qt::AlignCenter + + + + + + + test connection + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 220 + + + + + + + + clean dicom download folder + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.inject/src/internal/org_mitk_gui_qt_inject_Activator.cpp b/Plugins/org.mitk.gui.qt.inject/src/internal/org_mitk_gui_qt_inject_Activator.cpp new file mode 100644 index 0000000000..2153bc678d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/src/internal/org_mitk_gui_qt_inject_Activator.cpp @@ -0,0 +1,29 @@ +/*=================================================================== + +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 "org_mitk_gui_qt_inject_Activator.h" +#include "InjectView.h" + +namespace mitk +{ + void org_mitk_gui_qt_inject_Activator::start(ctkPluginContext *context) + { + BERRY_REGISTER_EXTENSION_CLASS(InjectView, context) + } + + void org_mitk_gui_qt_inject_Activator::stop(ctkPluginContext *context) { Q_UNUSED(context) } +} diff --git a/Plugins/org.mitk.gui.qt.inject/src/internal/org_mitk_gui_qt_inject_Activator.h b/Plugins/org.mitk.gui.qt.inject/src/internal/org_mitk_gui_qt_inject_Activator.h new file mode 100644 index 0000000000..8d68388788 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.inject/src/internal/org_mitk_gui_qt_inject_Activator.h @@ -0,0 +1,38 @@ +/*=================================================================== + +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 org_mitk_gui_qt_inject_Activator_h +#define org_mitk_gui_qt_inject_Activator_h + +#include + +namespace mitk +{ + class org_mitk_gui_qt_inject_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_inject") + Q_INTERFACES(ctkPluginActivator) + + public: + void start(ctkPluginContext *context); + void stop(ctkPluginContext *context); + + }; // org_mitk_gui_qt_inject_Activator +} + +#endif // org_mitk_gui_qt_inject_Activator_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 6b65664165..577f405398 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,549 +1,587 @@ /*=================================================================== 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 #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_HostURL = U("http://localhost"); + + auto host = m_HostURL; + + auto envHostURL = std::getenv("HOST_URL"); - m_restURL = U("http://localhost:8000/rest-srs"); - auto envHostURL = std::getenv("REST_URL"); if (envHostURL) { - m_restURL = mitk::RESTUtil::convertToTString(std::string(envHostURL)); + host = mitk::RESTUtil::convertToTString(std::string(envHostURL)); } + m_restURL = host.append(U("/rest-srs")); + utility::string_t pacsURL = U("http://193.174.48.78:8090"); auto envPacsURL = std::getenv("PACS_URL"); + if (envPacsURL) { pacsURL = mitk::RESTUtil::convertToTString(std::string(envPacsURL)); } - 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 Server + //StartServer(); // 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); } +void SegmentationReworkView::Activated() +{ + StartServer(); + MITK_INFO << "activated"; +} + +void SegmentationReworkView::Deactivated() +{ + MITK_INFO << "deactivated"; + m_ManagerService->HandleDeleteObserver(m_RequestHandler); +} + +void SegmentationReworkView::Visible() +{ + MITK_INFO << "visible"; +} + +void SegmentationReworkView::Hidden() +{ + MITK_INFO << "hidden"; +} + 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 = 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::StartServer() +{ + utility::string_t path = U("/inject"); + + auto pathEnv = std::getenv("SERVER_PATH"); + if (pathEnv) + { + path = mitk::RESTUtil::convertToTString(std::string(pathEnv)); + } + + utility::string_t port = U(":4040"); + utility::string_t address = m_HostURL; + address.append(port); + address.append(path); + // Setup listening server + m_ManagerService->ReceiveRequest(address, m_RequestHandler); + MITK_INFO << "Listening for requests at: " << utility::conversions::to_utf8string(address); +} + 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"}); mitk::DICOMweb::MitkUriBuilder queryBuilder(m_restURL + 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("/"); mitk::DICOMweb::MitkUriBuilder queryBuilder(m_restURL + 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 b31f8c4ff0..0dc17d1ddc 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,150 @@ /*=================================================================== 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 +#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 +class SegmentationReworkView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { 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); + virtual void Activated() override; + virtual void Deactivated() override; + virtual void Visible() override; + virtual void Hidden() override; + 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); + void StartServer(); + 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; mitk::DICOMweb m_DicomWeb; QWidget *m_Parent; utility::string_t m_restURL; + utility::string_t m_HostURL; }; #endif // SegmentationReworkView_h