diff --git a/Modules/Classification/CLMiniApps/CLOverlayRoiCenterOfMass.cpp b/Modules/Classification/CLMiniApps/CLOverlayRoiCenterOfMass.cpp index f7ef90d476..be37ab6a6d 100644 --- a/Modules/Classification/CLMiniApps/CLOverlayRoiCenterOfMass.cpp +++ b/Modules/Classification/CLMiniApps/CLOverlayRoiCenterOfMass.cpp @@ -1,174 +1,173 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkCLPolyToNrrd_cpp #define mitkCLPolyToNrrd_cpp #include "time.h" #include #include #include #include "mitkCommandLineParser.h" #include #include #include #include #include #include "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include "vtkRenderLargeImage.h" #include "vtkPNGWriter.h" #include #include typedef itk::Image< double, 3 > FloatImageType; typedef itk::Image< unsigned char, 3 > MaskImageType; template static void FindMostSampleSlice(itk::Image* mask, int & selectedSlice) { int idx = VImageDimension - 1; int size = mask->GetLargestPossibleRegion().GetSize()[idx]; std::vector numberOfSamples; numberOfSamples.resize(size,0); itk::ImageRegionIteratorWithIndex > mask1Iter(mask, mask->GetLargestPossibleRegion()); while (!mask1Iter.IsAtEnd()) { if (mask1Iter.Value() > 0) { numberOfSamples[mask1Iter.GetIndex()[idx]]+=1; } ++mask1Iter; } selectedSlice = 0; for (std::size_t i = 0; i < numberOfSamples.size(); ++i) { if (numberOfSamples[selectedSlice] < numberOfSamples[i]) selectedSlice = i; } } static void SaveSliceOrImageAsPNG(mitk::Image::Pointer image, mitk::Image::Pointer mask, std::string path, int index) { // Create a Standalone Datastorage for the single purpose of saving screenshots.. mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); QmitkRenderWindow renderWindow; renderWindow.GetRenderer()->SetDataStorage(ds); auto nodeI = mitk::DataNode::New(); nodeI->SetData(image); auto nodeM = mitk::DataNode::New(); nodeM->SetData(mask); ds->Add(nodeI); ds->Add(nodeM); auto geo = ds->ComputeBoundingGeometry3D(ds->GetAll()); - mitk::RenderingManager::GetInstance()->InitializeViews( - mask->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->InitializeViews(mask->GetTimeGeometry()); mitk::SliceNavigationController::Pointer sliceNaviController = renderWindow.GetSliceNavigationController(); sliceNaviController->SetViewDirection(mitk::SliceNavigationController::Axial); unsigned int numberOfSteps = 1; if (sliceNaviController) { numberOfSteps = sliceNaviController->GetSlice()->GetSteps(); sliceNaviController->GetSlice()->SetPos(numberOfSteps-index); } renderWindow.show(); renderWindow.resize(256, 256); //if (sliceNaviController) //{ // sliceNaviController->GetSlice()->SetPos(index); //} renderWindow.GetRenderer()->PrepareRender(); vtkRenderWindow* renderWindow2 = renderWindow.GetVtkRenderWindow(); mitk::BaseRenderer* baserenderer = mitk::BaseRenderer::GetInstance(renderWindow2); auto vtkRender = baserenderer->GetVtkRenderer(); vtkRender->GetRenderWindow()->WaitForCompletion(); vtkRenderLargeImage* magnifier = vtkRenderLargeImage::New(); magnifier->SetInput(vtkRender); magnifier->SetMagnification(3.0); std::stringstream ss; ss << path <<".png"; std::string tmpImageName; ss >> tmpImageName; auto fileWriter = vtkPNGWriter::New(); fileWriter->SetInputConnection(magnifier->GetOutputPort()); fileWriter->SetFileName(tmpImageName.c_str()); fileWriter->Write(); fileWriter->Delete(); } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("image", "i", mitkCommandLineParser::Image, "Input Image", "", us::Any(),false, false, false, mitkCommandLineParser::Input); parser.addArgument("mask", "m", mitkCommandLineParser::Image, "Input Image", "", us::Any(),false, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::Image, "Output Image", "", us::Any(),false, false, false, mitkCommandLineParser::Input); // Miniapp Infos parser.setCategory("Classification Tools"); parser.setTitle("Image with Overlay Plotter"); parser.setDescription("Plots "); parser.setContributor("German Cancer Research Center (DKFZ)"); std::map parsedArgs = parser.parseArguments(argc, argv); std::string imagePath = us::any_cast(parsedArgs["image"]); std::string maskPath = us::any_cast(parsedArgs["mask"]); std::string outputPath = us::any_cast(parsedArgs["output"]); if (parsedArgs.size()==0) { return EXIT_FAILURE; } if ( parsedArgs.count("help") || parsedArgs.count("h")) { return EXIT_SUCCESS; } std::string version = "Version: 1.0"; MITK_INFO << version; mitk::Image::Pointer image = mitk::IOUtil::Load(imagePath); mitk::Image::Pointer mask = mitk::IOUtil::Load(maskPath); // Create a QTApplication and a Datastorage // This is necessary in order to save screenshots of // each image / slice. QApplication qtapplication(argc, argv); QmitkRegisterClasses(); int currentSlice = 0; AccessByItk_1(mask, FindMostSampleSlice, currentSlice); SaveSliceOrImageAsPNG(image, mask, outputPath, currentSlice); return 0; } #endif diff --git a/Modules/Core/include/mitkRenderingManager.h b/Modules/Core/include/mitkRenderingManager.h index f0c7279010..37f1906f2e 100644 --- a/Modules/Core/include/mitkRenderingManager.h +++ b/Modules/Core/include/mitkRenderingManager.h @@ -1,405 +1,495 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#ifndef MITKRENDERINGMANAGER_H_HEADER_INCLUDED_C135A197 -#define MITKRENDERINGMANAGER_H_HEADER_INCLUDED_C135A197 +#ifndef MITKRENDERINGMANAGER_H +#define MITKRENDERINGMANAGER_H #include #include #include #include -#include -#include "mitkProperties.h" -#include "mitkPropertyList.h" -#include "mitkTimeGeometry.h" +#include +#include +#include #include class vtkRenderWindow; class vtkObject; namespace mitk { - class RenderingManager; class RenderingManagerFactory; class BaseGeometry; class SliceNavigationController; class BaseRenderer; class DataStorage; /** * \brief Manager for coordinating the rendering process. * * RenderingManager is a central instance retrieving and executing * RenderWindow update requests. Its main purpose is to coordinate * distributed requests which cannot be aware of each other - lacking the * knowledge of whether they are really necessary or not. For example, two * objects might determine that a specific RenderWindow needs to be updated. * This would result in one unnecessary update, if both executed the update * on their own. * * The RenderingManager addresses this by letting each such object * request an update, and waiting for other objects to possibly * issue the same request. The actual update will then only be executed at a * well-defined point in the main event loop (this may be each time after * event processing is done). * * Convinience methods for updating all RenderWindows which have been * registered with the RenderingManager exist. If theses methods are not * used, it is not required to register (add) RenderWindows prior to using * the RenderingManager. * * The methods #ForceImmediateUpdate() and #ForceImmediateUpdateAll() can * be used to force the RenderWindow update execution without any delay, * bypassing the request functionality. * * The interface of RenderingManager is platform independent. Platform * specific subclasses have to be implemented, though, to supply an * appropriate event issueing for controlling the update execution process. * See method documentation for a description of how this can be done. * * \sa TestingRenderingManager An "empty" RenderingManager implementation which * can be used in tests etc. * */ class MITKCORE_EXPORT RenderingManager : public itk::Object { public: mitkClassMacroItkParent(RenderingManager, itk::Object); typedef std::vector RenderWindowVector; typedef std::vector FloatVector; typedef std::vector BoolVector; typedef itk::SmartPointer DataStoragePointer; enum RequestType { REQUEST_UPDATE_ALL = 0, REQUEST_UPDATE_2DWINDOWS, REQUEST_UPDATE_3DWINDOWS }; static Pointer New(); /** Set the object factory which produces the desired platform specific * RenderingManager singleton instance. */ static void SetFactory(RenderingManagerFactory *factory); /** Get the object factory which produces the platform specific * RenderingManager instances. */ static const RenderingManagerFactory *GetFactory(); /** Returns true if a factory has already been set. */ static bool HasFactory(); /** Get the RenderingManager singleton instance. */ static RenderingManager *GetInstance(); /** Returns true if the singleton instance does already exist. */ static bool IsInstantiated(); /** Adds a RenderWindow. This is required if the methods #RequestUpdateAll * or #ForceImmediateUpdate are to be used. */ void AddRenderWindow(vtkRenderWindow *renderWindow); /** Removes a RenderWindow. */ void RemoveRenderWindow(vtkRenderWindow *renderWindow); /** Get a list of all registered RenderWindows */ const RenderWindowVector &GetAllRegisteredRenderWindows(); /** Requests an update for the specified RenderWindow, to be executed as * soon as the main loop is ready for rendering. */ void RequestUpdate(vtkRenderWindow *renderWindow); /** Immediately executes an update of the specified RenderWindow. */ void ForceImmediateUpdate(vtkRenderWindow *renderWindow); /** Requests all currently registered RenderWindows to be updated. * If only 2D or 3D windows should be updated, this can be specified * via the parameter requestType. */ void RequestUpdateAll(RequestType type = REQUEST_UPDATE_ALL); /** Immediately executes an update of all registered RenderWindows. * If only 2D or 3D windows should be updated, this can be specified * via the parameter requestType. */ void ForceImmediateUpdateAll(RequestType type = REQUEST_UPDATE_ALL); - /** Initializes the windows specified by requestType to the geometry of the - * given DataStorage. */ - // virtual bool InitializeViews( const DataStorage *storage, const DataNode* node = nullptr, - // RequestType type = REQUEST_UPDATE_ALL, bool preserveRoughOrientationInWorldSpace = false ); + /** + * @brief Initialize the render windows by the aggregated geometry of all objects that are held in + * the data storage. + * + * @param dataStorage The data storage from which the bounding object can be retrieved + */ + virtual void InitializeViewsByBoundingObjects(const DataStorage* dataStorage); - /** Initializes the windows specified by requestType to the given - * geometry. PLATFORM SPECIFIC. TODO: HOW IS THIS PLATFORM SPECIFIC? - * Throws an exception if bounding box has 0 extent due to exceeding - * double precision range. */ + /** + * @brief Initialize the render windows specified by "type" to the given geometry. + * + * Throws an exception if bounding box has 0 extent due to exceeding double precision range. + * + * @param geometry The geometry to be used to initialize / update a + * render window's time and slice navigation controller + * @param type The type of update request: + * - REQUEST_UPDATE_ALL will initialize / update the + * time and slice navigation controller of all retrieved render windows + * - REQUEST_UPDATE_2DWINDOWS will only initialize / update the + * time and slice navigation controller of 2D render windows + * - REQUEST_UPDATE_3DWINDOWS will only initialize / update the + * time and slice navigation controller of 3D render windows + * @param resetCamera If this parameter is set to true, the camera controller will be + * set / fit to the center of the rendered image. If set to false, only the + * the slice navigation controller is reset to the geometry without changing + * the camera view / position. + */ virtual bool InitializeViews(const BaseGeometry *geometry, RequestType type = REQUEST_UPDATE_ALL, bool resetCamera = true); + + /** + * @brief Initialize the render windows specified by "type" to the given geometry. + * + * Throws an exception if bounding box has 0 extent due to exceeding double precision range. + * + * @param geometry The geometry to be used to initialize / update a + * render window's time- and slice navigation controller + * @param type The type of update request: + * - REQUEST_UPDATE_ALL will initialize / update the + * time- and slice navigation controller of all retrieved render windows + * - REQUEST_UPDATE_2DWINDOWS will only initialize / update the + * time- and slice navigation controller of 2D render windows + * - REQUEST_UPDATE_3DWINDOWS will only initialize / update the + * time- and slice navigation controller of 3D render windows + * @param resetCamera If this parameter is set to true, the camera controller will be + * set / fit to the center of the rendered image. If set to false, only the + * the slice navigation controller is reset to the geometry without changing + * the camera view / position. + */ virtual bool InitializeViews(const TimeGeometry *geometry, RequestType type = REQUEST_UPDATE_ALL, bool resetCamera = true); - /** Initializes the windows to the default viewing direction - * (geomtry information is NOT changed). PLATFORM SPECIFIC. */ + /** + * @brief Initialize the render windows specified by "type" to the default viewing direction + * without updating the geometry information. + * + * @param type The type of update request: + * - REQUEST_UPDATE_ALL will initialize the + * slice navigation controller of all retrieved render windows + * - REQUEST_UPDATE_2DWINDOWS will only initialize the + * slice navigation controller of 2D render windows + * - REQUEST_UPDATE_3DWINDOWS will only initialize the + * slice navigation controller of 3D render windows + */ virtual bool InitializeViews(RequestType type = REQUEST_UPDATE_ALL); - /** Initializes the specified window to the geometry of the given - * DataNode. Set "initializeGlobalTimeSNC" to true in order to use this - * geometry as global TimeGeometry. PLATFORM SPECIFIC. */ - // virtual bool InitializeView( vtkRenderWindow *renderWindow, const DataStorage* ds, const DataNode* node = nullptr, - // bool initializeGlobalTimeSNC = false ); - - /** Initializes the specified window to the given geometry. Set - * "initializeGlobalTimeSNC" to true in order to use this geometry as - * global TimeGeometry. PLATFORM SPECIFIC. */ + /** + * @brief Initialize the specified render window to the given geometry. + * + * Throws an exception if bounding box has 0 extent due to exceeding double precision range. + * + * @param renderWindow The specifid render window to update + * @param geometry The geometry to be used to initialize / update the + * render window's time- and slice navigation controller + * @param initializeGlobalTime If this parameter is set to true, the time navigation controller will be + * initialized / updated with the given geometry. If set to false, the geometry + * of the time navigation controller is not updated. + * @param resetCamera If this parameter is set to true, the camera controller will be + * set / fit to the center of the rendered image. If set to false, only the + * the slice navigation controller is reset to the geometry without changing + * the camera view / position. + */ virtual bool InitializeView(vtkRenderWindow *renderWindow, const BaseGeometry *geometry, - bool initializeGlobalTimeSNC = false, + bool initializeGlobalTime = true, bool resetCamera = true); + + /** + * @brief Initialize the specified render window to the given geometry. + * + * Throws an exception if bounding box has 0 extent due to exceeding double precision range. + * + * @param renderWindow The specifid render window to update + * @param geometry The geometry to be used to initialize / update the + * render window's time- and slice navigation controller + * @param initializeGlobalTime If this parameter is set to true, the time navigation controller will be + * initialized / updated with the given geometry. If set to false, the geometry + * of the time navigation controller is not updated. + * @param resetCamera If this parameter is set to true, the camera controller will be + * set / fit to the center of the rendered image. If set to false, only the + * the slice navigation controller is reset to the geometry without changing + * the camera view / position. + */ virtual bool InitializeView(vtkRenderWindow *renderWindow, const TimeGeometry *geometry, - bool initializeGlobalTimeSNC = false, + bool initializeGlobalTime = true, bool resetCamera = true); - /** Initializes the specified window to the default viewing direction - * (geomtry information is NOT changed). PLATFORM SPECIFIC. */ - virtual bool InitializeView(vtkRenderWindow *renderWindow); - /** - * @brief Initializes the renderwindows by the aggregated geometry of - * all objects that are held in the data storage. - * This is basically a global reinit - * @param dataStorage The data storage from which the bounding object can be retrieved - */ - virtual void InitializeViewsByBoundingObjects(const DataStorage *dataStorage); + * @brief Initialize the specified render window to the default viewing direction + * without updating the geometry information. + * + * @param renderWindow The specifid render window to update + */ + virtual bool InitializeView(vtkRenderWindow *renderWindow); /** Gets the (global) SliceNavigationController responsible for * time-slicing. */ const SliceNavigationController *GetTimeNavigationController() const; /** Gets the (global) SliceNavigationController responsible for * time-slicing. */ SliceNavigationController *GetTimeNavigationController(); ~RenderingManager() override; /** Executes all pending requests. This method has to be called by the * system whenever a RenderingManager induced request event occurs in * the system pipeline (see concrete RenderingManager implementations). */ virtual void ExecutePendingRequests(); bool IsRendering() const; void AbortRendering(); /** En-/Disable LOD increase globally. */ itkSetMacro(LODIncreaseBlocked, bool); /** En-/Disable LOD increase globally. */ itkGetMacro(LODIncreaseBlocked, bool); /** En-/Disable LOD increase globally. */ itkBooleanMacro(LODIncreaseBlocked); /** En-/Disable LOD abort mechanism. */ itkSetMacro(LODAbortMechanismEnabled, bool); /** En-/Disable LOD abort mechanism. */ itkGetMacro(LODAbortMechanismEnabled, bool); /** En-/Disable LOD abort mechanism. */ itkBooleanMacro(LODAbortMechanismEnabled); /** Force a sub-class to start a timer for a pending hires-rendering request */ virtual void StartOrResetTimer(){}; /** To be called by a sub-class from a timer callback */ void ExecutePendingHighResRenderingRequest(); virtual void DoStartRendering(){}; virtual void DoMonitorRendering(){}; virtual void DoFinishAbortRendering(){}; int GetNextLOD(BaseRenderer *renderer); /** Set current LOD (nullptr means all renderers)*/ void SetMaximumLOD(unsigned int max); void SetShading(bool state, unsigned int lod); bool GetShading(unsigned int lod); void SetClippingPlaneStatus(bool status); bool GetClippingPlaneStatus(); void SetShadingValues(float ambient, float diffuse, float specular, float specpower); FloatVector &GetShadingValues(); /** Returns a property list */ PropertyList::Pointer GetPropertyList() const; /** Returns a property from m_PropertyList */ BaseProperty *GetProperty(const char *propertyKey) const; /** Sets or adds (if not present) a property in m_PropertyList */ void SetProperty(const char *propertyKey, BaseProperty *propertyValue); /** - * \brief Setter / Getter for internal DataStorage + * \brief Setter for internal DataStorage * - * Sets / returns the mitk::DataStorage that is used internally. This instance holds all mitk::DataNodes that are + * Sets the DataStorage that is used internally. This instance holds all DataNodes that are * rendered by the registered BaseRenderers. * * If this DataStorage is changed at runtime by calling SetDataStorage(), * all currently registered BaseRenderers are automatically given the correct instance. * When a new BaseRenderer is added, it is automatically initialized with the currently active DataStorage. */ - void SetDataStorage(mitk::DataStorage *storage); + void SetDataStorage(DataStorage *storage); /** - * \brief Setter / Getter for internal DataStorage + * \brief Getter for internal DataStorage * - * Sets / returns the mitk::DataStorage that is used internally. This instance holds all mitk::DataNodes that are + * Returns the DataStorage that is used internally. This instance holds all DataNodes that are * rendered by the registered BaseRenderers. - * - * If this DataStorage is changed at runtime by calling SetDataStorage(), - * all currently registered BaseRenderers are automatically given the correct instance. - * When a new BaseRenderer is added, it is automatically initialized with the currently active DataStorage. */ - mitk::DataStorage *GetDataStorage(); + itkGetMacro(DataStorage, DataStorage*); + itkGetConstMacro(DataStorage, DataStorage*); /** * @brief Sets a flag to the given renderwindow to indicated that it has the focus e.g. has been clicked recently. * @param focusWindow */ void SetRenderWindowFocus(vtkRenderWindow *focusWindow); - itkGetMacro(FocusedRenderWindow, vtkRenderWindow *); itkSetMacro(ConstrainedPanningZooming, bool); - - itkGetMacro(AntiAliasing, AntiAliasing); + itkGetConstMacro(ConstrainedPanningZooming, bool); void SetAntiAliasing(AntiAliasing antiAliasing); + itkGetConstMacro(AntiAliasing, AntiAliasing); protected: enum { RENDERING_INACTIVE = 0, RENDERING_REQUESTED, RENDERING_INPROGRESS }; RenderingManager(); /** Abstract method for generating a system specific event for rendering * request. This method is called whenever an update is requested */ virtual void GenerateRenderingRequestEvent() = 0; virtual void InitializePropertyList(); bool m_UpdatePending; typedef std::map RendererIntMap; typedef std::map RendererBoolMap; RendererBoolMap m_RenderingAbortedMap; RendererIntMap m_NextLODMap; unsigned int m_MaxLOD; bool m_LODIncreaseBlocked; bool m_LODAbortMechanismEnabled; BoolVector m_ShadingEnabled; bool m_ClippingPlaneEnabled; FloatVector m_ShadingValues; static void RenderingStartCallback(vtkObject *caller, unsigned long eid, void *clientdata, void *calldata); static void RenderingProgressCallback(vtkObject *caller, unsigned long eid, void *clientdata, void *calldata); static void RenderingEndCallback(vtkObject *caller, unsigned long eid, void *clientdata, void *calldata); typedef std::map RenderWindowList; RenderWindowList m_RenderWindowList; RenderWindowVector m_AllRenderWindows; struct RenderWindowCallbacks { vtkCallbackCommand *commands[3u]; }; typedef std::map RenderWindowCallbacksList; RenderWindowCallbacksList m_RenderWindowCallbacksList; itk::SmartPointer m_TimeNavigationController; static RenderingManager::Pointer s_Instance; static RenderingManagerFactory *s_RenderingManagerFactory; PropertyList::Pointer m_PropertyList; DataStoragePointer m_DataStorage; bool m_ConstrainedPanningZooming; private: - void InternalViewInitialization(mitk::BaseRenderer *baseRenderer, - const mitk::TimeGeometry *geometry, + + /** + * @brief Initialize the specified renderer to the given geometry. + * + * @param baseRenderer The specifid renderer to update + * @param geometry The geometry to be used to initialize / update the + * render window's slice navigation controller + * @param boundingBoxInitialized If this parameter is set to true, the slice navigation controller will be + * initialized / updated with the given geometry. If set to false, the geometry + * of the slice navigation controller is not updated. + * @param mapperID The mapper ID is used to define if the given renderer is a 2D or a 3D renderer. + * In case of a 2D renderer and if "boundingBoxInitialized" is set to true (slice + * navigation controller will be updated with a new geometry), the position of the + * slice navigation controller is set to the center slice. + * @param resetCamera If this parameter is set to true, the camera controller will be + * set / fit to the center of the rendered image. If set to false, only the + * the slice navigation controller is reset to the geometry without changing + * the camera view / position. + */ + void InternalViewInitialization(BaseRenderer *baseRenderer, + const TimeGeometry *geometry, bool boundingBoxInitialized, int mapperID, bool resetCamera); + /** + * @brief Extend the bounding box of the given geometry to make sure the bounding box has an extent bigger than + * zero in any direction. + * + * @param originalGeometry The original geometry to be extended + * @param modifiedGeometry The modified geometry where the new bounds (extended bounding box) are used / set + */ + bool ExtendGeometryForBoundingBox(const TimeGeometry* originalGeometry, TimeGeometry::Pointer& modifiedGeometry); + vtkRenderWindow *m_FocusedRenderWindow; AntiAliasing m_AntiAliasing; }; #pragma GCC visibility push(default) itkEventMacro(RenderingManagerEvent, itk::AnyEvent); itkEventMacro(RenderingManagerViewsInitializedEvent, RenderingManagerEvent); #pragma GCC visibility pop itkEventMacroDeclaration(FocusChangedEvent, itk::AnyEvent); /** * Generic RenderingManager implementation for "non-rendering-plattform", * e.g. for tests. Its factory (TestingRenderingManagerFactory) is * automatically on start-up and is used by default if not other * RenderingManagerFactory is instantiated explicitly thereafter. * (see mitkRenderingManager.cpp) */ class MITKCORE_EXPORT TestingRenderingManager : public RenderingManager { public: mitkClassMacro(TestingRenderingManager, RenderingManager); itkFactorylessNewMacro(Self); itkCloneMacro(Self); protected: void GenerateRenderingRequestEvent() override {}; }; } // namespace mitk -#endif /* MITKRenderingManager_H_HEADER_INCLUDED_C135A197 */ +#endif // MITKRENDERINGMANAGER_H diff --git a/Modules/Core/src/Controllers/mitkRenderingManager.cpp b/Modules/Core/src/Controllers/mitkRenderingManager.cpp index c4b707d00a..eb09085e41 100644 --- a/Modules/Core/src/Controllers/mitkRenderingManager.cpp +++ b/Modules/Core/src/Controllers/mitkRenderingManager.cpp @@ -1,776 +1,772 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#include "mitkRenderingManager.h" -#include "mitkBaseRenderer.h" -#include "mitkCameraController.h" -#include "mitkNodePredicateNot.h" -#include "mitkNodePredicateProperty.h" -#include "mitkProportionalTimeGeometry.h" -#include "mitkRenderingManagerFactory.h" +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include "mitkNumericTypes.h" -#include #include -#include #include -#include - namespace mitk { itkEventMacroDefinition(FocusChangedEvent, itk::AnyEvent); RenderingManager::Pointer RenderingManager::s_Instance = nullptr; RenderingManagerFactory *RenderingManager::s_RenderingManagerFactory = nullptr; RenderingManager::RenderingManager() : m_UpdatePending(false), m_MaxLOD(1), m_LODIncreaseBlocked(false), m_LODAbortMechanismEnabled(false), m_ClippingPlaneEnabled(false), m_TimeNavigationController(SliceNavigationController::New()), m_DataStorage(nullptr), m_ConstrainedPanningZooming(true), m_FocusedRenderWindow(nullptr), m_AntiAliasing(AntiAliasing::FastApproximate) { m_ShadingEnabled.assign(3, false); m_ShadingValues.assign(4, 0.0); InitializePropertyList(); } RenderingManager::~RenderingManager() { // Decrease reference counts of all registered vtkRenderWindows for // proper destruction RenderWindowVector::iterator it; for (it = m_AllRenderWindows.begin(); it != m_AllRenderWindows.end(); ++it) { (*it)->UnRegister(nullptr); auto callbacks_it = this->m_RenderWindowCallbacksList.find(*it); if (callbacks_it != this->m_RenderWindowCallbacksList.end()) { (*it)->RemoveObserver(callbacks_it->second.commands[0u]); (*it)->RemoveObserver(callbacks_it->second.commands[1u]); (*it)->RemoveObserver(callbacks_it->second.commands[2u]); } } } void RenderingManager::SetFactory(RenderingManagerFactory *factory) { s_RenderingManagerFactory = factory; } const RenderingManagerFactory *RenderingManager::GetFactory() { return s_RenderingManagerFactory; } bool RenderingManager::HasFactory() { if (RenderingManager::s_RenderingManagerFactory) { return true; } else { return false; } } RenderingManager::Pointer RenderingManager::New() { const RenderingManagerFactory *factory = GetFactory(); if (factory == nullptr) return nullptr; return factory->CreateRenderingManager(); } RenderingManager *RenderingManager::GetInstance() { if (!RenderingManager::s_Instance) { if (s_RenderingManagerFactory) { s_Instance = s_RenderingManagerFactory->CreateRenderingManager(); } } return s_Instance; } bool RenderingManager::IsInstantiated() { if (RenderingManager::s_Instance) return true; else return false; } void RenderingManager::AddRenderWindow(vtkRenderWindow *renderWindow) { if (renderWindow && (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.end())) { m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_AllRenderWindows.push_back(renderWindow); if (m_DataStorage.IsNotNull()) - mitk::BaseRenderer::GetInstance(renderWindow)->SetDataStorage(m_DataStorage.GetPointer()); + BaseRenderer::GetInstance(renderWindow)->SetDataStorage(m_DataStorage.GetPointer()); // Register vtkRenderWindow instance renderWindow->Register(nullptr); // Add callbacks for rendering abort mechanism // BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow ); vtkCallbackCommand *startCallbackCommand = vtkCallbackCommand::New(); startCallbackCommand->SetCallback(RenderingManager::RenderingStartCallback); renderWindow->AddObserver(vtkCommand::StartEvent, startCallbackCommand); vtkCallbackCommand *progressCallbackCommand = vtkCallbackCommand::New(); progressCallbackCommand->SetCallback(RenderingManager::RenderingProgressCallback); renderWindow->AddObserver(vtkCommand::AbortCheckEvent, progressCallbackCommand); vtkCallbackCommand *endCallbackCommand = vtkCallbackCommand::New(); endCallbackCommand->SetCallback(RenderingManager::RenderingEndCallback); renderWindow->AddObserver(vtkCommand::EndEvent, endCallbackCommand); RenderWindowCallbacks callbacks; callbacks.commands[0u] = startCallbackCommand; callbacks.commands[1u] = progressCallbackCommand; callbacks.commands[2u] = endCallbackCommand; this->m_RenderWindowCallbacksList[renderWindow] = callbacks; // Delete vtk variables correctly startCallbackCommand->Delete(); progressCallbackCommand->Delete(); endCallbackCommand->Delete(); } } void RenderingManager::RemoveRenderWindow(vtkRenderWindow *renderWindow) { if (m_RenderWindowList.erase(renderWindow)) { auto callbacks_it = this->m_RenderWindowCallbacksList.find(renderWindow); if (callbacks_it != this->m_RenderWindowCallbacksList.end()) { renderWindow->RemoveObserver(callbacks_it->second.commands[0u]); renderWindow->RemoveObserver(callbacks_it->second.commands[1u]); renderWindow->RemoveObserver(callbacks_it->second.commands[2u]); this->m_RenderWindowCallbacksList.erase(callbacks_it); } auto rw_it = std::find(m_AllRenderWindows.begin(), m_AllRenderWindows.end(), renderWindow); if (rw_it != m_AllRenderWindows.cend()) { // Decrease reference count for proper destruction (*rw_it)->UnRegister(nullptr); m_AllRenderWindows.erase(rw_it); } } } const RenderingManager::RenderWindowVector &RenderingManager::GetAllRegisteredRenderWindows() { return m_AllRenderWindows; } void RenderingManager::RequestUpdate(vtkRenderWindow *renderWindow) { // If the renderWindow is not valid, we do not want to inadvertantly create // an entry in the m_RenderWindowList map. It is possible if the user is // regularly calling AddRenderer and RemoveRenderer for a rendering update // to come into this method with a renderWindow pointer that is valid in the // sense that the window does exist within the application, but that // renderWindow has been temporarily removed from this RenderingManager for // performance reasons. if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.cend()) { return; } m_RenderWindowList[renderWindow] = RENDERING_REQUESTED; if (!m_UpdatePending) { m_UpdatePending = true; this->GenerateRenderingRequestEvent(); } } void RenderingManager::ForceImmediateUpdate(vtkRenderWindow *renderWindow) { // If the renderWindow is not valid, we do not want to inadvertantly create // an entry in the m_RenderWindowList map. It is possible if the user is // regularly calling AddRenderer and RemoveRenderer for a rendering update // to come into this method with a renderWindow pointer that is valid in the // sense that the window does exist within the application, but that // renderWindow has been temporarily removed from this RenderingManager for // performance reasons. if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.cend()) { return; } // Erase potentially pending requests for this window m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_UpdatePending = false; // Immediately repaint this window (implementation platform specific) // If the size is 0 it crashes int *size = renderWindow->GetSize(); if (0 != size[0] && 0 != size[1]) { // prepare the camera etc. before rendering // Note: this is a very important step which should be called before the VTK render! // If you modify the camera anywhere else or after the render call, the scene cannot be seen. - auto *vPR = dynamic_cast(mitk::BaseRenderer::GetInstance(renderWindow)); + auto *vPR = dynamic_cast(BaseRenderer::GetInstance(renderWindow)); if (vPR) vPR->PrepareRender(); // Execute rendering renderWindow->Render(); } } void RenderingManager::RequestUpdateAll(RequestType type) { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { this->RequestUpdate(it->first); } } } void RenderingManager::ForceImmediateUpdateAll(RequestType type) { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { // Immediately repaint this window (implementation platform specific) // If the size is 0, it crashes this->ForceImmediateUpdate(it->first); } } } - void RenderingManager::InitializeViewsByBoundingObjects(const DataStorage *ds) + void RenderingManager::InitializeViewsByBoundingObjects(const DataStorage* dataStorage) { - if (!ds) + if (nullptr == dataStorage) + { return; + } // get all nodes that have not set "includeInBoundingBox" to false - mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New( - mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); + auto pred = NodePredicateNot::New(NodePredicateProperty::New("includeInBoundingBox", BoolProperty::New(false))); + DataStorage::SetOfObjects::ConstPointer filteredNodes = dataStorage->GetSubset(pred); - mitk::DataStorage::SetOfObjects::ConstPointer rs = ds->GetSubset(pred); - // calculate bounding geometry of these nodes - auto bounds = ds->ComputeBoundingGeometry3D(rs, "visible"); + TimeGeometry::ConstPointer boundingGeometry; + if (!filteredNodes->empty()) + { + // calculate bounding geometry of these nodes + boundingGeometry = dataStorage->ComputeBoundingGeometry3D(filteredNodes, "visible"); + } // initialize the views to the bounding geometry - this->InitializeViews(bounds); + this->InitializeViews(boundingGeometry); } - // TODO_GOETZ - // Remove old function, so only this one is working. - bool RenderingManager::InitializeViews(const BaseGeometry *dataGeometry, - RequestType type, + bool RenderingManager::InitializeViews(const BaseGeometry *geometry, RequestType type, bool resetCamera) { ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); - propTimeGeometry->Initialize(dynamic_cast(dataGeometry->Clone().GetPointer()), 1); - return InitializeViews(propTimeGeometry, type, resetCamera); + propTimeGeometry->Initialize(dynamic_cast(geometry->Clone().GetPointer()), 1); + return this->InitializeViews(propTimeGeometry, type, resetCamera); } - bool RenderingManager::InitializeViews(const TimeGeometry *dataGeometry, - RequestType type, + bool RenderingManager::InitializeViews(const TimeGeometry *geometry, RequestType type, bool resetCamera) { - MITK_DEBUG << "initializing views"; - bool boundingBoxInitialized = false; - TimeGeometry::ConstPointer timeGeometry = dataGeometry; TimeGeometry::Pointer modifiedGeometry = nullptr; - if (dataGeometry != nullptr) + try { - modifiedGeometry = dataGeometry->Clone(); + boundingBoxInitialized = this->ExtendGeometryForBoundingBox(geometry, modifiedGeometry); } - - int warningLevel = vtkObject::GetGlobalWarningDisplay(); - vtkObject::GlobalWarningDisplayOff(); - - if ((timeGeometry.IsNotNull()) && - (timeGeometry->GetBoundingBoxInWorld()->GetDiagonalLength2() > mitk::eps)) + catch (Exception& exception) { - boundingBoxInitialized = true; - } - - if (timeGeometry.IsNotNull()) - { // make sure bounding box has an extent bigger than zero in any direction - // clone the input geometry - // Old Geometry3D::Pointer modifiedGeometry = dynamic_cast( dataGeometry->Clone().GetPointer() ); - assert(modifiedGeometry.IsNotNull()); - for (TimeStepType step = 0; step < modifiedGeometry->CountTimeSteps(); ++step) - { - BaseGeometry::BoundsArrayType newBounds = modifiedGeometry->GetGeometryForTimeStep(step)->GetBounds(); - for (unsigned int dimension = 0; (2 * dimension) < newBounds.Size(); dimension++) - { - // check for equality but for an epsilon - if (Equal(newBounds[2 * dimension], newBounds[2 * dimension + 1])) - { - newBounds[2 * dimension + 1] += 1; - if (Equal( - newBounds[2 * dimension], - newBounds[2 * dimension + 1])) // newBounds will still be equal if values are beyond double precision - { - mitkThrow() << "One dimension of object data has zero length, please make sure you're not using numbers " - "beyond double precision as coordinates."; - } - } - } - modifiedGeometry->GetGeometryForTimeStep(step)->SetBounds(newBounds); - } + mitkReThrow(exception); } - timeGeometry = modifiedGeometry; - RenderWindowList::const_iterator it; - for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) + RenderWindowVector allRenderWindows = this->GetAllRegisteredRenderWindows(); + RenderWindowVector::const_iterator it; + for (it = allRenderWindows.cbegin(); it != allRenderWindows.cend(); ++it) { - mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(it->first); - - baseRenderer->SetConstrainZoomingAndPanning(m_ConstrainedPanningZooming); + BaseRenderer *baseRenderer = BaseRenderer::GetInstance(*it); + baseRenderer->SetConstrainZoomingAndPanning(this->GetConstrainedPanningZooming()); int id = baseRenderer->GetMapperID(); - if (((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || - ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)))) + if ((type == REQUEST_UPDATE_ALL) || + ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || + ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { - this->InternalViewInitialization(baseRenderer, timeGeometry, boundingBoxInitialized, id, resetCamera); + this->InternalViewInitialization(baseRenderer, modifiedGeometry, boundingBoxInitialized, id, resetCamera); } } if (boundingBoxInitialized) { - m_TimeNavigationController->SetInputWorldTimeGeometry(timeGeometry); + this->GetTimeNavigationController()->SetInputWorldTimeGeometry(modifiedGeometry); } - m_TimeNavigationController->Update(); + this->GetTimeNavigationController()->Update(); this->RequestUpdateAll(type); - vtkObject::SetGlobalWarningDisplay(warningLevel); - - // Inform listeners that views have been initialized - this->InvokeEvent(mitk::RenderingManagerViewsInitializedEvent()); + // inform listeners that views have been initialized + this->InvokeEvent(RenderingManagerViewsInitializedEvent()); return boundingBoxInitialized; } bool RenderingManager::InitializeViews(RequestType type) { - RenderWindowList::const_iterator it; - for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) + const RenderWindowVector allRenderWindows = this->GetAllRegisteredRenderWindows(); + RenderWindowVector::const_iterator it; + for (it = allRenderWindows.cbegin(); it != allRenderWindows.cend(); ++it) { - mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(it->first); + BaseRenderer *baseRenderer = BaseRenderer::GetInstance(*it); int id = baseRenderer->GetMapperID(); - if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || - ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) + if ((type == REQUEST_UPDATE_ALL) || + ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || + ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { - mitk::SliceNavigationController *nc = - - baseRenderer->GetSliceNavigationController(); - - // Re-initialize view direction - nc->SetViewDirectionToDefault(); - - // Update the SNC - nc->Update(); + this->InternalViewInitialization(baseRenderer, nullptr, false, id, false); } } this->RequestUpdateAll(type); + // inform listeners that views have been initialized + this->InvokeEvent(RenderingManagerViewsInitializedEvent()); + return true; } - bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow, - const BaseGeometry *geometry, - bool initializeGlobalTimeSNC, - bool resetCamera) + bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow, const BaseGeometry *geometry, + bool initializeGlobalTime, bool resetCamera) { ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(dynamic_cast(geometry->Clone().GetPointer()), 1); - return InitializeView(renderWindow, propTimeGeometry, initializeGlobalTimeSNC, resetCamera); + return this->InitializeView(renderWindow, propTimeGeometry, initializeGlobalTime, resetCamera); } - bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow, - const TimeGeometry *geometry, - bool initializeGlobalTimeSNC, - bool resetCamera) + bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow, const TimeGeometry *geometry, + bool initializeGlobalTime, bool resetCamera) { bool boundingBoxInitialized = false; - int warningLevel = vtkObject::GetGlobalWarningDisplay(); - vtkObject::GlobalWarningDisplayOff(); - - if ((geometry != nullptr) && - (geometry->GetBoundingBoxInWorld()->GetDiagonalLength2() > mitk::eps)) + TimeGeometry::Pointer modifiedGeometry = nullptr; + try { - boundingBoxInitialized = true; + boundingBoxInitialized = this->ExtendGeometryForBoundingBox(geometry, modifiedGeometry); + } + catch (Exception &exception) + { + mitkReThrow(exception); } - mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow); + BaseRenderer *baseRenderer = BaseRenderer::GetInstance(renderWindow); + baseRenderer->SetConstrainZoomingAndPanning(this->GetConstrainedPanningZooming()); int id = baseRenderer->GetMapperID(); + this->InternalViewInitialization(baseRenderer, modifiedGeometry, boundingBoxInitialized, id, resetCamera); - this->InternalViewInitialization(baseRenderer, geometry, boundingBoxInitialized, id, resetCamera); - - if (boundingBoxInitialized && initializeGlobalTimeSNC) + if (boundingBoxInitialized && initializeGlobalTime) { - m_TimeNavigationController->SetInputWorldTimeGeometry(geometry); + this->GetTimeNavigationController()->SetInputWorldTimeGeometry(modifiedGeometry); } - m_TimeNavigationController->Update(); + + this->GetTimeNavigationController()->Update(); this->RequestUpdate(renderWindow); - vtkObject::SetGlobalWarningDisplay(warningLevel); + // inform listeners that views have been initialized + this->InvokeEvent(RenderingManagerViewsInitializedEvent()); return boundingBoxInitialized; } bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow) { - mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow); - - mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); - - // Re-initialize view direction - nc->SetViewDirectionToDefault(); - - // Update the SNC - nc->Update(); + BaseRenderer *baseRenderer = BaseRenderer::GetInstance(renderWindow); + int id = baseRenderer->GetMapperID(); + this->InternalViewInitialization(baseRenderer, nullptr, false, id, false); this->RequestUpdate(renderWindow); + // inform listeners that views have been initialized + this->InvokeEvent(RenderingManagerViewsInitializedEvent()); + return true; } - void RenderingManager::InternalViewInitialization(mitk::BaseRenderer *baseRenderer, - const mitk::TimeGeometry *geometry, - bool boundingBoxInitialized, - int mapperID, - bool resetCamera) + void RenderingManager::InternalViewInitialization(BaseRenderer *baseRenderer, const TimeGeometry *geometry, + bool boundingBoxInitialized, int mapperID, bool resetCamera) { - mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); + SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); if (boundingBoxInitialized) { // Set geometry for NC nc->SetInputWorldTimeGeometry(geometry); nc->Update(); if (resetCamera) { if (mapperID == BaseRenderer::Standard2D) { // For 2D SNCs, steppers are set so that the cross is centered in the image nc->GetSlice()->SetPos(nc->GetSlice()->GetSteps() / 2); baseRenderer->GetCameraController()->Fit(); } else if (mapperID == BaseRenderer::Standard3D) { baseRenderer->GetCameraController()->SetViewToAnterior(); } } } else { nc->Update(); } } + bool RenderingManager::ExtendGeometryForBoundingBox(const TimeGeometry *geometry, + TimeGeometry::Pointer& modifiedGeometry) + { + bool boundingBoxInitialized = false; + + if (nullptr == geometry) + { + return boundingBoxInitialized; + } + + modifiedGeometry = geometry->Clone(); + if (modifiedGeometry.IsNull()) + { + return boundingBoxInitialized; + } + + if (modifiedGeometry->GetBoundingBoxInWorld()->GetDiagonalLength2() > eps) + { + boundingBoxInitialized = true; + } + + // make sure bounding box has an extent bigger than zero in any direction + for (TimeStepType step = 0; step < modifiedGeometry->CountTimeSteps(); ++step) + { + BaseGeometry::BoundsArrayType newBounds = modifiedGeometry->GetGeometryForTimeStep(step)->GetBounds(); + for (unsigned int dimension = 0; (2 * dimension) < newBounds.Size(); dimension++) + { + // check for equality but for an epsilon + if (Equal(newBounds[2 * dimension], newBounds[2 * dimension + 1])) + { + newBounds[2 * dimension + 1] += 1; + if (Equal( + newBounds[2 * dimension], + newBounds[2 * dimension + 1])) // newBounds will still be equal if values are beyond double precision + { + mitkThrow() << "One dimension of object data has zero length, please make sure you're not using numbers " + "beyond double precision as coordinates."; + } + } + } + modifiedGeometry->GetGeometryForTimeStep(step)->SetBounds(newBounds); + } + + return boundingBoxInitialized; + } + const SliceNavigationController *RenderingManager::GetTimeNavigationController() const { return m_TimeNavigationController.GetPointer(); } SliceNavigationController *RenderingManager::GetTimeNavigationController() { return m_TimeNavigationController.GetPointer(); } void RenderingManager::ExecutePendingRequests() { m_UpdatePending = false; // Satisfy all pending update requests RenderWindowList::const_iterator it; int i = 0; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it, ++i) { if (it->second == RENDERING_REQUESTED) { this->ForceImmediateUpdate(it->first); } } } void RenderingManager::RenderingStartCallback(vtkObject *caller, unsigned long, void *, void *) { auto renderingManager = RenderingManager::GetInstance(); auto renderWindow = dynamic_cast(caller); if (nullptr != renderWindow) renderingManager->m_RenderWindowList[renderWindow] = RENDERING_INPROGRESS; renderingManager->m_UpdatePending = false; } void RenderingManager::RenderingProgressCallback(vtkObject *caller, unsigned long, void *, void *) { auto renderingManager = RenderingManager::GetInstance(); if (renderingManager->m_LODAbortMechanismEnabled) { auto renderWindow = dynamic_cast(caller); if (nullptr != renderWindow) { auto renderer = BaseRenderer::GetInstance(renderWindow); if (nullptr != renderer && 0 < renderer->GetNumberOfVisibleLODEnabledMappers()) renderingManager->DoMonitorRendering(); } } } void RenderingManager::RenderingEndCallback(vtkObject *caller, unsigned long, void *, void *) { auto renderWindow = dynamic_cast(caller); + if (nullptr == renderWindow) + { + return; + } - if (nullptr != renderWindow) + auto renderer = BaseRenderer::GetInstance(renderWindow); + if (nullptr == renderer) { - auto renderer = BaseRenderer::GetInstance(renderWindow); + return; + } - if (nullptr != renderer) - { - auto renderingManager = RenderingManager::GetInstance(); - renderingManager->m_RenderWindowList[renderer->GetRenderWindow()] = RENDERING_INACTIVE; + auto renderingManager = RenderingManager::GetInstance(); + renderingManager->m_RenderWindowList[renderer->GetRenderWindow()] = RENDERING_INACTIVE; - if (0 < renderer->GetNumberOfVisibleLODEnabledMappers()) - { - if (0 == renderingManager->m_NextLODMap[renderer]) - { - renderingManager->StartOrResetTimer(); - } - else - { - renderingManager->m_NextLODMap[renderer] = 0; - } - } + if (0 < renderer->GetNumberOfVisibleLODEnabledMappers()) + { + if (0 == renderingManager->m_NextLODMap[renderer]) + { + renderingManager->StartOrResetTimer(); + } + else + { + renderingManager->m_NextLODMap[renderer] = 0; } } } bool RenderingManager::IsRendering() const { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { if (it->second == RENDERING_INPROGRESS) { return true; } } return false; } void RenderingManager::AbortRendering() { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { if (it->second == RENDERING_INPROGRESS) { it->first->SetAbortRender(true); m_RenderingAbortedMap[BaseRenderer::GetInstance(it->first)] = true; } } } int RenderingManager::GetNextLOD(BaseRenderer *renderer) { if (renderer != nullptr) { return m_NextLODMap[renderer]; } else { return 0; } } void RenderingManager::ExecutePendingHighResRenderingRequest() { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { BaseRenderer *renderer = BaseRenderer::GetInstance(it->first); if (renderer->GetNumberOfVisibleLODEnabledMappers() > 0) { if (m_NextLODMap[renderer] == 0) { m_NextLODMap[renderer] = 1; RequestUpdate(it->first); } } } } void RenderingManager::SetMaximumLOD(unsigned int max) { m_MaxLOD = max; } // enable/disable shading void RenderingManager::SetShading(bool state, unsigned int lod) { if (lod > m_MaxLOD) { itkWarningMacro(<< "LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return; } m_ShadingEnabled[lod] = state; } bool RenderingManager::GetShading(unsigned int lod) { if (lod > m_MaxLOD) { itkWarningMacro(<< "LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return false; } return m_ShadingEnabled[lod]; } // enable/disable the clipping plane void RenderingManager::SetClippingPlaneStatus(bool status) { m_ClippingPlaneEnabled = status; } bool RenderingManager::GetClippingPlaneStatus() { return m_ClippingPlaneEnabled; } void RenderingManager::SetShadingValues(float ambient, float diffuse, float specular, float specpower) { m_ShadingValues[0] = ambient; m_ShadingValues[1] = diffuse; m_ShadingValues[2] = specular; m_ShadingValues[3] = specpower; } RenderingManager::FloatVector &RenderingManager::GetShadingValues() { return m_ShadingValues; } void RenderingManager::InitializePropertyList() { if (m_PropertyList.IsNull()) { m_PropertyList = PropertyList::New(); } this->SetProperty("coupled-zoom", BoolProperty::New(false)); this->SetProperty("coupled-plane-rotation", BoolProperty::New(false)); this->SetProperty("MIP-slice-rendering", BoolProperty::New(false)); } PropertyList::Pointer RenderingManager::GetPropertyList() const { return m_PropertyList; } BaseProperty *RenderingManager::GetProperty(const char *propertyKey) const { return m_PropertyList->GetProperty(propertyKey); } void RenderingManager::SetProperty(const char *propertyKey, BaseProperty *propertyValue) { m_PropertyList->SetProperty(propertyKey, propertyValue); } void RenderingManager::SetDataStorage(DataStorage *storage) { if (storage != nullptr) { m_DataStorage = storage; RenderingManager::RenderWindowVector::const_iterator iter; for (iter = m_AllRenderWindows.cbegin(); iter < m_AllRenderWindows.cend(); ++iter) { - mitk::BaseRenderer::GetInstance((*iter))->SetDataStorage(m_DataStorage.GetPointer()); + BaseRenderer::GetInstance((*iter))->SetDataStorage(m_DataStorage.GetPointer()); } } } - mitk::DataStorage *RenderingManager::GetDataStorage() { return m_DataStorage; } void RenderingManager::SetRenderWindowFocus(vtkRenderWindow *focusWindow) { if (focusWindow != m_FocusedRenderWindow) { if (!focusWindow || (m_RenderWindowList.find(focusWindow) != m_RenderWindowList.cend())) { m_FocusedRenderWindow = focusWindow; this->InvokeEvent(FocusChangedEvent()); return; } MITK_ERROR << "Tried to set a RenderWindow that does not exist."; } } void RenderingManager::SetAntiAliasing(AntiAliasing antiAliasing) { if (m_AntiAliasing != antiAliasing) { - auto renderingManager = mitk::RenderingManager::GetInstance(); + auto renderingManager = RenderingManager::GetInstance(); auto renderWindows = renderingManager->GetAllRegisteredRenderWindows(); for (auto renderWindow : renderWindows) { auto renderers = renderWindow->GetRenderers(); if (nullptr != renderers) { renderers->InitTraversal(); auto renderer = renderers->GetNextItem(); while (nullptr != renderer) { renderer->SetUseFXAA(AntiAliasing::FastApproximate == antiAliasing); renderer = renderers->GetNextItem(); } renderingManager->RequestUpdate(renderWindow); } } m_AntiAliasing = antiAliasing; } } // Create and register generic RenderingManagerFactory. TestingRenderingManagerFactory renderingManagerFactory; } // namespace diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp index 8a18b5e708..2ab4f4d8be 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp @@ -1,881 +1,880 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include "QmitkDataStorageTreeModel.h" #include "QmitkDataStorageTreeModelInternalItem.h" #include "QmitkNodeDescriptorManager.h" #include #include #include #include #include #include #include #include #include QmitkDataStorageTreeModel::QmitkDataStorageTreeModel(mitk::DataStorage *_DataStorage, bool _PlaceNewNodesOnTop, QObject *parent) : QAbstractItemModel(parent), m_DataStorage(nullptr), m_PlaceNewNodesOnTop(_PlaceNewNodesOnTop), m_Root(nullptr), m_BlockDataStorageEvents(false), m_AllowHierarchyChange(false) { this->SetDataStorage(_DataStorage); } QmitkDataStorageTreeModel::~QmitkDataStorageTreeModel() { // set data storage to 0 = remove all listeners this->SetDataStorage(nullptr); m_Root->Delete(); m_Root = nullptr; } mitk::DataNode::Pointer QmitkDataStorageTreeModel::GetNode(const QModelIndex &index) const { return this->TreeItemFromIndex(index)->GetDataNode(); } const mitk::DataStorage::Pointer QmitkDataStorageTreeModel::GetDataStorage() const { return m_DataStorage.Lock(); } QModelIndex QmitkDataStorageTreeModel::index(int row, int column, const QModelIndex &parent) const { TreeItem *parentItem; if (!parent.isValid()) parentItem = m_Root; else parentItem = static_cast(parent.internalPointer()); TreeItem *childItem = parentItem->GetChild(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } int QmitkDataStorageTreeModel::rowCount(const QModelIndex &parent) const { TreeItem *parentTreeItem = this->TreeItemFromIndex(parent); return parentTreeItem->GetChildCount(); } Qt::ItemFlags QmitkDataStorageTreeModel::flags(const QModelIndex &index) const { if (index.isValid()) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } else { return Qt::ItemIsDropEnabled; } } int QmitkDataStorageTreeModel::columnCount(const QModelIndex & /* parent = QModelIndex() */) const { return 1; } QModelIndex QmitkDataStorageTreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); TreeItem *childItem = this->TreeItemFromIndex(index); TreeItem *parentItem = childItem->GetParent(); if (parentItem == m_Root) return QModelIndex(); return this->createIndex(parentItem->GetIndex(), 0, parentItem); } QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItemFromIndex(const QModelIndex &index) const { if (index.isValid()) return static_cast(index.internalPointer()); else return m_Root; } Qt::DropActions QmitkDataStorageTreeModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkDataStorageTreeModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } bool QmitkDataStorageTreeModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent) { // Early exit, returning true, but not actually doing anything (ignoring data). if (action == Qt::IgnoreAction) { return true; } // Note, we are returning true if we handled it, and false otherwise bool returnValue = false; if (data->hasFormat("application/x-qabstractitemmodeldatalist")) { returnValue = true; // First we extract a Qlist of TreeItem* pointers. QList listOfItemsToDrop = ToTreeItemPtrList(data); if (listOfItemsToDrop.empty()) { return false; } // Retrieve the TreeItem* where we are dropping stuff, and its parent. TreeItem *dropItem = this->TreeItemFromIndex(parent); TreeItem *parentItem = dropItem->GetParent(); // If item was dropped onto empty space, we select the root node if (dropItem == m_Root) { parentItem = m_Root; } // Dragging and Dropping is only allowed within the same parent, so use the first item in list to validate. // (otherwise, you could have a derived image such as a segmentation, and assign it to another image). // NOTE: We are assuming the input list is valid... i.e. when it was dragged, all the items had the same parent. // Determine whether or not the drag and drop operation is a valid one. // Examples of invalid operations include: // - dragging nodes with different parents // - dragging nodes from one parent to another parent, if m_AllowHierarchyChange is false // - dragging a node on one of its child nodes (only relevant if m_AllowHierarchyChange is true) bool isValidDragAndDropOperation(true); // different parents { TreeItem *firstParent = listOfItemsToDrop[0]->GetParent(); QList::iterator diIter; for (diIter = listOfItemsToDrop.begin() + 1; diIter != listOfItemsToDrop.end(); diIter++) { if (firstParent != (*diIter)->GetParent()) { isValidDragAndDropOperation = false; break; } } } // dragging from one parent to another if ((!m_AllowHierarchyChange) && isValidDragAndDropOperation) { if (row == -1) // drag onto a node { isValidDragAndDropOperation = listOfItemsToDrop[0]->GetParent() == parentItem; } else // drag between nodes { isValidDragAndDropOperation = listOfItemsToDrop[0]->GetParent() == dropItem; } } // dragging on a child node of one the dragged nodes { QList::iterator diIter; for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { TreeItem *tempItem = dropItem; while (tempItem != m_Root) { tempItem = tempItem->GetParent(); if (tempItem == *diIter) { isValidDragAndDropOperation = false; } } } } if (!isValidDragAndDropOperation) return isValidDragAndDropOperation; if (listOfItemsToDrop[0] != dropItem && isValidDragAndDropOperation) { // Retrieve the index of where we are dropping stuff. QModelIndex parentModelIndex = this->IndexFromTreeItem(parentItem); int dragIndex = 0; // Iterate through the list of TreeItem (which may be at non-consecutive indexes). QList::iterator diIter; for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { TreeItem *itemToDrop = *diIter; // if the item is dragged down we have to compensate its final position for the // fact it is deleted lateron, this only applies if it is dragged within the same level if ((itemToDrop->GetIndex() < row) && (itemToDrop->GetParent() == dropItem)) { dragIndex = 1; } // Here we assume that as you remove items, one at a time, that GetIndex() will be valid. this->beginRemoveRows( this->IndexFromTreeItem(itemToDrop->GetParent()), itemToDrop->GetIndex(), itemToDrop->GetIndex()); itemToDrop->GetParent()->RemoveChild(itemToDrop); this->endRemoveRows(); } // row = -1 dropped on an item, row != -1 dropped in between two items // Select the target index position, or put it at the end of the list. int dropIndex = 0; if (row != -1) { if (dragIndex == 0) dropIndex = std::min(row, parentItem->GetChildCount() - 1); else dropIndex = std::min(row - 1, parentItem->GetChildCount() - 1); } else { dropIndex = dropItem->GetIndex(); } QModelIndex dropItemModelIndex = this->IndexFromTreeItem(dropItem); if ((row == -1 && dropItemModelIndex.row() == -1) || dropItemModelIndex.row() > parentItem->GetChildCount()) dropIndex = parentItem->GetChildCount() - 1; // Now insert items again at the drop item position if (m_AllowHierarchyChange) { this->beginInsertRows(dropItemModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); } else { this->beginInsertRows(parentModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); } for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { // dropped on node, behaviour depends on preference setting if (m_AllowHierarchyChange) { auto dataStorage = m_DataStorage.Lock(); m_BlockDataStorageEvents = true; mitk::DataNode::Pointer droppedNode = (*diIter)->GetDataNode(); mitk::DataNode *dropOntoNode = dropItem->GetDataNode(); dataStorage->Remove(droppedNode); dataStorage->Add(droppedNode, dropOntoNode); m_BlockDataStorageEvents = false; dropItem->InsertChild((*diIter), dropIndex); } else { if (row == -1) // drag onto a node { parentItem->InsertChild((*diIter), dropIndex); } else // drag between nodes { dropItem->InsertChild((*diIter), dropIndex); } } dropIndex++; } this->endInsertRows(); // Change Layers to match. this->AdjustLayerProperty(); } } else if (data->hasFormat("application/x-mitk-datanodes")) { returnValue = true; int numberOfNodesDropped = 0; QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); mitk::DataNode *node = nullptr; foreach (node, dataNodeList) { auto datastorage = m_DataStorage.Lock(); if (node && datastorage.IsNotNull() && !datastorage->Exists(node)) { m_DataStorage.Lock()->Add(node); mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { - mitk::RenderingManager::GetInstance()->InitializeViews( - basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->InitializeViews(basedata->GetTimeGeometry()); numberOfNodesDropped++; } } } // Only do a rendering update, if we actually dropped anything. if (numberOfNodesDropped > 0) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } return returnValue; } QStringList QmitkDataStorageTreeModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << "application/x-qabstractitemmodeldatalist"; types << "application/x-mitk-datanodes"; return types; } QMimeData *QmitkDataStorageTreeModel::mimeData(const QModelIndexList &indexes) const { return mimeDataFromModelIndexList(indexes); } QMimeData *QmitkDataStorageTreeModel::mimeDataFromModelIndexList(const QModelIndexList &indexes) { QMimeData *ret = new QMimeData; QString treeItemAddresses(""); QString dataNodeAddresses(""); QByteArray baTreeItemPtrs; QByteArray baDataNodePtrs; QDataStream dsTreeItemPtrs(&baTreeItemPtrs, QIODevice::WriteOnly); QDataStream dsDataNodePtrs(&baDataNodePtrs, QIODevice::WriteOnly); for (int i = 0; i < indexes.size(); i++) { TreeItem *treeItem = static_cast(indexes.at(i).internalPointer()); dsTreeItemPtrs << reinterpret_cast(treeItem); dsDataNodePtrs << reinterpret_cast(treeItem->GetDataNode().GetPointer()); // --------------- deprecated ----------------- unsigned long long treeItemAddress = reinterpret_cast(treeItem); unsigned long long dataNodeAddress = reinterpret_cast(treeItem->GetDataNode().GetPointer()); QTextStream(&treeItemAddresses) << treeItemAddress; QTextStream(&dataNodeAddresses) << dataNodeAddress; if (i != indexes.size() - 1) { QTextStream(&treeItemAddresses) << ","; QTextStream(&dataNodeAddresses) << ","; } // -------------- end deprecated ------------- } // ------------------ deprecated ----------------- ret->setData("application/x-qabstractitemmodeldatalist", QByteArray(treeItemAddresses.toLatin1())); ret->setData("application/x-mitk-datanodes", QByteArray(dataNodeAddresses.toLatin1())); // --------------- end deprecated ----------------- ret->setData(QmitkMimeTypes::DataStorageTreeItemPtrs, baTreeItemPtrs); ret->setData(QmitkMimeTypes::DataNodePtrs, baDataNodePtrs); return ret; } QVariant QmitkDataStorageTreeModel::data(const QModelIndex &index, int role) const { mitk::DataNode *dataNode = this->TreeItemFromIndex(index)->GetDataNode(); // get name of treeItem (may also be edited) QString nodeName = QString::fromStdString(dataNode->GetName()); if (nodeName.isEmpty()) { nodeName = "unnamed"; } if (role == Qt::DisplayRole) return nodeName; else if (role == Qt::ToolTipRole) return nodeName; else if (role == Qt::DecorationRole) { QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (role == Qt::CheckStateRole) { return dataNode->IsVisible(nullptr); } else if (role == QmitkDataNodeRole) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } else if (role == QmitkDataNodeRawPointerRole) { return QVariant::fromValue(dataNode); } return QVariant(); } bool QmitkDataStorageTreeModel::DicomPropertiesExists(const mitk::DataNode &node) const { bool propertiesExists = false; mitk::BaseProperty *seriesDescription_deprecated = (node.GetProperty("dicom.series.SeriesDescription")); mitk::BaseProperty *studyDescription_deprecated = (node.GetProperty("dicom.study.StudyDescription")); mitk::BaseProperty *patientsName_deprecated = (node.GetProperty("dicom.patient.PatientsName")); mitk::BaseProperty *seriesDescription = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103e).c_str())); mitk::BaseProperty *studyDescription = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x1030).c_str())); mitk::BaseProperty *patientsName = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0010, 0x0010).c_str())); if (patientsName != nullptr && studyDescription != nullptr && seriesDescription != nullptr) { if ((!patientsName->GetValueAsString().empty()) && (!studyDescription->GetValueAsString().empty()) && (!seriesDescription->GetValueAsString().empty())) { propertiesExists = true; } } /** Code coveres the deprecated property naming for backwards compatibility */ if (patientsName_deprecated != nullptr && studyDescription_deprecated != nullptr && seriesDescription_deprecated != nullptr) { if ((!patientsName_deprecated->GetValueAsString().empty()) && (!studyDescription_deprecated->GetValueAsString().empty()) && (!seriesDescription_deprecated->GetValueAsString().empty())) { propertiesExists = true; } } return propertiesExists; } QVariant QmitkDataStorageTreeModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_Root) return QString::fromStdString(m_Root->GetDataNode()->GetName()); return QVariant(); } void QmitkDataStorageTreeModel::SetDataStorage(mitk::DataStorage *_DataStorage) { if (m_DataStorage != _DataStorage) // dont take the same again { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { // remove Listener for the data storage itself dataStorage->RemoveObserver(m_DataStorageDeletedTag); // remove listeners for the nodes dataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkDataStorageTreeModel::AddNode)); dataStorage->ChangedNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetNodeModified)); dataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::RemoveNode)); } this->beginResetModel(); // take over the new data storage m_DataStorage = _DataStorage; // delete the old root (if necessary, create new) if (m_Root) m_Root->Delete(); mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); rootDataNode->SetName("Data Manager"); m_Root = new TreeItem(rootDataNode, nullptr); dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { // add Listener for the data storage itself auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkDataStorageTreeModel::SetDataStorageDeleted); m_DataStorageDeletedTag = dataStorage->AddObserver(itk::DeleteEvent(), command); // add listeners for the nodes dataStorage->AddNodeEvent.AddListener(mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::AddNode)); dataStorage->ChangedNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetNodeModified)); dataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::RemoveNode)); // finally add all nodes to the model this->Update(); } this->endResetModel(); } } void QmitkDataStorageTreeModel::SetDataStorageDeleted() { this->SetDataStorage(nullptr); } void QmitkDataStorageTreeModel::AddNodeInternal(const mitk::DataNode *node) { if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != nullptr) return; // find out if we have a root node TreeItem *parentTreeItem = m_Root; QModelIndex index; mitk::DataNode *parentDataNode = this->GetParentNode(node); if (parentDataNode) // no top level data node { parentTreeItem = m_Root->Find(parentDataNode); // find the corresponding tree item if (!parentTreeItem) { this->AddNode(parentDataNode); parentTreeItem = m_Root->Find(parentDataNode); if (!parentTreeItem) return; } // get the index of this parent with the help of the grand parent index = this->createIndex(parentTreeItem->GetIndex(), 0, parentTreeItem); } // add node if (m_PlaceNewNodesOnTop) { // emit beginInsertRows event beginInsertRows(index, 0, 0); parentTreeItem->InsertChild(new TreeItem(const_cast(node)), 0); } else { int firstRowWithASiblingBelow = 0; int nodeLayer = -1; node->GetIntProperty("layer", nodeLayer); for (TreeItem* siblingTreeItem: parentTreeItem->GetChildren()) { int siblingLayer = -1; if (mitk::DataNode* siblingNode = siblingTreeItem->GetDataNode()) { siblingNode->GetIntProperty("layer", siblingLayer); } if (nodeLayer > siblingLayer) { break; } ++firstRowWithASiblingBelow; } beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); parentTreeItem->InsertChild(new TreeItem(const_cast(node)), firstRowWithASiblingBelow); } // emit endInsertRows event endInsertRows(); if(m_PlaceNewNodesOnTop) { this->AdjustLayerProperty(); } } void QmitkDataStorageTreeModel::AddNode(const mitk::DataNode *node) { if (node == nullptr || m_BlockDataStorageEvents || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != nullptr) return; this->AddNodeInternal(node); } void QmitkDataStorageTreeModel::SetPlaceNewNodesOnTop(bool _PlaceNewNodesOnTop) { m_PlaceNewNodesOnTop = _PlaceNewNodesOnTop; } void QmitkDataStorageTreeModel::RemoveNodeInternal(const mitk::DataNode *node) { if (!m_Root) return; TreeItem *treeItem = m_Root->Find(node); if (!treeItem) return; // return because there is no treeitem containing this node TreeItem *parentTreeItem = treeItem->GetParent(); QModelIndex parentIndex = this->IndexFromTreeItem(parentTreeItem); // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) this->beginRemoveRows(parentIndex, treeItem->GetIndex(), treeItem->GetIndex()); // remove node std::vector children = treeItem->GetChildren(); delete treeItem; // emit endRemoveRows event endRemoveRows(); // move all children of deleted node into its parent for (std::vector::iterator it = children.begin(); it != children.end(); it++) { // emit beginInsertRows event beginInsertRows(parentIndex, parentTreeItem->GetChildCount(), parentTreeItem->GetChildCount()); // add nodes again parentTreeItem->AddChild(*it); // emit endInsertRows event endInsertRows(); } this->AdjustLayerProperty(); } void QmitkDataStorageTreeModel::RemoveNode(const mitk::DataNode *node) { if (node == nullptr || m_BlockDataStorageEvents) return; this->RemoveNodeInternal(node); } void QmitkDataStorageTreeModel::SetNodeModified(const mitk::DataNode *node) { TreeItem *treeItem = m_Root->Find(node); if (treeItem) { TreeItem *parentTreeItem = treeItem->GetParent(); // as the root node should not be removed one should always have a parent item if (!parentTreeItem) return; QModelIndex index = this->createIndex(treeItem->GetIndex(), 0, treeItem); // now emit the dataChanged signal emit dataChanged(index, index); } } mitk::DataNode *QmitkDataStorageTreeModel::GetParentNode(const mitk::DataNode *node) const { mitk::DataNode *dataNode = nullptr; mitk::DataStorage::SetOfObjects::ConstPointer _Sources = m_DataStorage.Lock()->GetSources(node); if (_Sources->Size() > 0) dataNode = _Sources->front(); return dataNode; } bool QmitkDataStorageTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { mitk::DataNode *dataNode = this->TreeItemFromIndex(index)->GetDataNode(); if (!dataNode) return false; if (role == Qt::EditRole && !value.toString().isEmpty()) { dataNode->SetStringProperty("name", value.toString().toStdString().c_str()); mitk::PlanarFigure *planarFigure = dynamic_cast(dataNode->GetData()); if (planarFigure != nullptr) mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (role == Qt::CheckStateRole) { // Please note: value.toInt() returns 2, independentely from the actual checkstate of the index element. // Therefore the checkstate is being estimated again here. QVariant qcheckstate = index.data(Qt::CheckStateRole); int checkstate = qcheckstate.toInt(); bool isVisible = bool(checkstate); dataNode->SetVisibility(!isVisible); emit nodeVisibilityChanged(); } // inform listeners about changes emit dataChanged(index, index); return true; } bool QmitkDataStorageTreeModel::setHeaderData(int /*section*/, Qt::Orientation /*orientation*/, const QVariant & /* value */, int /*role = Qt::EditRole*/) { return false; } void QmitkDataStorageTreeModel::AdjustLayerProperty() { /// transform the tree into an array and set the layer property descending std::vector vec; this->TreeToVector(m_Root, vec); int i = vec.size() - 1; for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) { mitk::DataNode::Pointer dataNode = (*it)->GetDataNode(); bool fixedLayer = false; if (!(dataNode->GetBoolProperty("fixedLayer", fixedLayer) && fixedLayer)) dataNode->SetIntProperty("layer", i); --i; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataStorageTreeModel::TreeToVector(TreeItem *parent, std::vector &vec) const { TreeItem *current; for (int i = 0; i < parent->GetChildCount(); ++i) { current = parent->GetChild(i); this->TreeToVector(current, vec); vec.push_back(current); } } QModelIndex QmitkDataStorageTreeModel::IndexFromTreeItem(TreeItem *item) const { if (item == m_Root) return QModelIndex(); else return this->createIndex(item->GetIndex(), 0, item); } QList QmitkDataStorageTreeModel::GetNodeSet() const { QList res; if (m_Root) this->TreeToNodeSet(m_Root, res); return res; } void QmitkDataStorageTreeModel::TreeToNodeSet(TreeItem *parent, QList &vec) const { TreeItem *current; for (int i = 0; i < parent->GetChildCount(); ++i) { current = parent->GetChild(i); vec.push_back(current->GetDataNode()); this->TreeToNodeSet(current, vec); } } QModelIndex QmitkDataStorageTreeModel::GetIndex(const mitk::DataNode *node) const { if (m_Root) { TreeItem *item = m_Root->Find(node); if (item) return this->IndexFromTreeItem(item); } return QModelIndex(); } QList QmitkDataStorageTreeModel::ToTreeItemPtrList(const QMimeData *mimeData) { if (mimeData == nullptr || !mimeData->hasFormat(QmitkMimeTypes::DataStorageTreeItemPtrs)) { return QList(); } return ToTreeItemPtrList(mimeData->data(QmitkMimeTypes::DataStorageTreeItemPtrs)); } QList QmitkDataStorageTreeModel::ToTreeItemPtrList(const QByteArray &ba) { QList result; QDataStream ds(ba); while (!ds.atEnd()) { quintptr treeItemPtr; ds >> treeItemPtr; result.push_back(reinterpret_cast(treeItemPtr)); } return result; } void QmitkDataStorageTreeModel::Update() { auto datastorage = m_DataStorage.Lock(); if (datastorage.IsNotNull()) { mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = datastorage->GetAll(); /// Regardless the value of this preference, the new nodes must not be inserted /// at the top now, but at the position according to their layer. bool newNodesWereToBePlacedOnTop = m_PlaceNewNodesOnTop; m_PlaceNewNodesOnTop = false; for (const auto& node : *_NodeSet) { this->AddNodeInternal(node); } m_PlaceNewNodesOnTop = newNodesWereToBePlacedOnTop; /// Adjust the layers to ensure that derived nodes are above their sources. this->AdjustLayerProperty(); } } void QmitkDataStorageTreeModel::SetAllowHierarchyChange(bool allowHierarchyChange) { m_AllowHierarchyChange = allowHierarchyChange; } diff --git a/Modules/ToFUI/Qmitk/QmitkToFSurfaceGenerationWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFSurfaceGenerationWidget.cpp index 35de081d33..2275b3dd6c 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFSurfaceGenerationWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFSurfaceGenerationWidget.cpp @@ -1,290 +1,290 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkToFSurfaceGenerationWidget.h" #include #include //QT headers #include #include #include + #include const std::string QmitkToFSurfaceGenerationWidget::VIEW_ID = "org.mitk.views.qmitktofsurfacegenerationwidget"; QmitkToFSurfaceGenerationWidget::QmitkToFSurfaceGenerationWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) , m_Controls(nullptr), m_ToFDistanceImageToSurfaceFilter(nullptr), m_ToFImageGrabber(nullptr), m_CameraIntrinsics(nullptr), m_Active(false) { CreateQtPartControl(this); } QmitkToFSurfaceGenerationWidget::~QmitkToFSurfaceGenerationWidget() { } void QmitkToFSurfaceGenerationWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFSurfaceGenerationWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); this->OnShowAdvancedOptionsCheckboxChecked(false); } } void QmitkToFSurfaceGenerationWidget::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_Compute3DDataCheckbox), SIGNAL(toggled(bool)), this, SLOT(OnCompute3DDataCheckboxChecked(bool)) ); connect( (QObject*)(m_Controls->m_DistanceColorMapCheckbox), SIGNAL(toggled(bool)), this, SLOT(OnDistanceColorMapCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_RGBTextureCheckbox), SIGNAL(toggled(bool)), this, SLOT(OnRGBTextureCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_TriangulationThresholdSpinbox), SIGNAL(valueChanged(double)), this, SLOT(OnTriangulationThresholdSpinBoxChanged()) ); connect( (QObject*)(m_Controls->m_ShowAdvancedOptionsCheckbox), SIGNAL(toggled(bool)), this, SLOT(OnShowAdvancedOptionsCheckboxChecked(bool)) ); connect( (QObject*)(m_Controls->m_RepresentationCombobox), SIGNAL(currentIndexChanged(int)),(QObject*) this, SLOT(OnRepresentationChanged(int)) ); connect( (QObject*)(m_Controls->m_ReconstructionCombobox), SIGNAL(currentIndexChanged(int)),(QObject*) this, SLOT(OnReconstructionChanged(int)) ); } } mitk::ToFDistanceImageToSurfaceFilter::Pointer QmitkToFSurfaceGenerationWidget::GetToFDistanceImageToSurfaceFilter() { return m_ToFDistanceImageToSurfaceFilter; } void QmitkToFSurfaceGenerationWidget::OnShowAdvancedOptionsCheckboxChecked(bool checked) { this->m_Controls->m_TextureGroupBox->setVisible(checked); this->m_Controls->m_TriangulationThresholdSpinbox->setVisible(checked); this->m_Controls->m_ReconstructionCombobox->setVisible(checked); this->m_Controls->m_RepresentationCombobox->setVisible(checked); this->m_Controls->label->setVisible(checked); this->m_Controls->label_2->setVisible(checked); this->m_Controls->label_3->setVisible(checked); } void QmitkToFSurfaceGenerationWidget::Initialize(mitk::ToFDistanceImageToSurfaceFilter::Pointer filter, mitk::ToFImageGrabber::Pointer grabber, mitk::CameraIntrinsics::Pointer intrinsics, mitk::DataNode::Pointer surface, vtkSmartPointer camera, bool generateSurface, bool showAdvancedOptions) { m_ToFDistanceImageToSurfaceFilter = filter; m_ToFImageGrabber = grabber; m_CameraIntrinsics = intrinsics; m_Active = true; m_Camera3d = camera; bool hasSurface = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasSurface", hasSurface); if(hasSurface) { this->m_Surface = mitk::Surface::New(); } else { this->m_Surface = this->m_ToFDistanceImageToSurfaceFilter->GetOutput(0); } m_SurfaceNode = surface; m_SurfaceNode->SetData(m_Surface); this->FindReconstructionModeProperty(); m_Controls->m_ShowAdvancedOptionsCheckbox->setChecked(showAdvancedOptions); this->OnShowAdvancedOptionsCheckboxChecked(showAdvancedOptions); m_Controls->m_Compute3DDataCheckbox->setChecked(generateSurface); } bool QmitkToFSurfaceGenerationWidget::IsActive() { if(!m_Active) { MITK_ERROR << "QmitkToFSurfaceGenerationWidget is not active - please call QmitkToFSurfaceGenerationWidget::Initialize() first"; } return m_Active; } void QmitkToFSurfaceGenerationWidget::OnTriangulationThresholdSpinBoxChanged() { if(IsActive()) { this->m_ToFDistanceImageToSurfaceFilter->SetTriangulationThreshold( this->m_Controls->m_TriangulationThresholdSpinbox->value() ); this->m_ToFImageGrabber->GetCameraDevice()->SetFloatProperty("TriangulationThreshold", this->m_Controls->m_TriangulationThresholdSpinbox->value()); } } void QmitkToFSurfaceGenerationWidget::OnReconstructionChanged(int index) { if(IsActive()) { mitk::ToFDistanceImageToSurfaceFilter::ReconstructionModeType type = mitk::ToFDistanceImageToSurfaceFilter::WithInterPixelDistance; switch (index) { case 0: { type = mitk::ToFDistanceImageToSurfaceFilter::WithInterPixelDistance; break; } case 1: { type = mitk::ToFDistanceImageToSurfaceFilter::WithOutInterPixelDistance; break; } case 2: { type = mitk::ToFDistanceImageToSurfaceFilter::Kinect; break; } default: { MITK_ERROR << "ReconstructionModeType does not exist or is not known in QmitkToFSurfaceGenerationWidget."; break; } } this->m_ToFDistanceImageToSurfaceFilter->SetReconstructionMode( type ); } } void QmitkToFSurfaceGenerationWidget::OnRepresentationChanged(int index) { if(IsActive()) { bool generateTriangularMesh = false; //PointCloud case if( index == 0) //Surface case { generateTriangularMesh = true; } this->m_ToFDistanceImageToSurfaceFilter->SetGenerateTriangularMesh(generateTriangularMesh); this->m_ToFImageGrabber->GetCameraDevice()->SetBoolProperty("GenerateTriangularMesh", generateTriangularMesh); this->m_ToFDistanceImageToSurfaceFilter->SetTriangulationThreshold( this->m_Controls->m_TriangulationThresholdSpinbox->value() ); this->m_ToFImageGrabber->GetCameraDevice()->SetFloatProperty("TriangulationThreshold", this->m_Controls->m_TriangulationThresholdSpinbox->value()); this->m_Controls->m_TriangulationThresholdSpinbox->setEnabled(generateTriangularMesh); } } void QmitkToFSurfaceGenerationWidget::OnRGBTextureCheckBoxChecked(bool checked) { if(IsActive()) { if(m_ToFImageGrabber->GetBoolProperty("HasRGBImage")) { if (checked) { // enable texture this->m_SurfaceNode->SetProperty("Surface.Texture",mitk::SmartPointerProperty::New(this->m_ToFImageGrabber->GetOutput(3))); } else { // disable texture this->m_SurfaceNode->GetPropertyList()->DeleteProperty("Surface.Texture"); } } } } void QmitkToFSurfaceGenerationWidget::OnDistanceColorMapCheckBoxChecked(bool checked) { if(m_SurfaceNode.IsNotNull()) { this->m_SurfaceNode->SetBoolProperty("scalar visibility", checked); } } bool QmitkToFSurfaceGenerationWidget::UpdateSurface() { if(IsActive()) { //##### Code for surface ##### if (m_Controls->m_Compute3DDataCheckbox->isChecked()) { bool hasSurface = false; this->m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasSurface", hasSurface); if(hasSurface) { mitk::SmartPointerProperty::Pointer surfaceProp = dynamic_cast< mitk::SmartPointerProperty * >(this->m_ToFImageGrabber->GetCameraDevice()->GetProperty("ToFSurface")); this->m_Surface->SetVtkPolyData( dynamic_cast< mitk::Surface* >( surfaceProp->GetSmartPointer().GetPointer() )->GetVtkPolyData() ); } else { this->m_Surface = m_ToFDistanceImageToSurfaceFilter->GetOutput(0); } //update pipeline this->m_Surface->Update(); return true; } //##### End code for surface ##### } return false; } void QmitkToFSurfaceGenerationWidget::OnCompute3DDataCheckboxChecked(bool checked) { if(checked) { //initialize the surface once MITK_DEBUG << "OnSurfaceCheckboxChecked true"; this->m_SurfaceNode->SetData(this->m_Surface); this->OnRepresentationChanged(m_Controls->m_RepresentationCombobox->currentIndex()); //we need to initialize (reinit) the surface, to make it fit into the renderwindow - mitk::RenderingManager::GetInstance()->InitializeViews( - this->m_Surface->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS, true); + mitk::RenderingManager::GetInstance()->InitializeViews(this->m_Surface->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); // correctly place the vtk camera for appropriate surface rendering //1m distance to camera should be a nice default value for most cameras m_Camera3d->SetPosition(0,0,0); m_Camera3d->SetViewUp(0,-1,0); m_Camera3d->SetFocalPoint(0,0,1); if (this->m_CameraIntrinsics.IsNotNull()) { // compute view angle from camera intrinsics m_Camera3d->SetViewAngle(mitk::ToFProcessingCommon::CalculateViewAngle(m_CameraIntrinsics,m_ToFImageGrabber->GetCaptureWidth())); } else { m_Camera3d->SetViewAngle(45); } m_Camera3d->SetClippingRange(1, 10000); } } void QmitkToFSurfaceGenerationWidget::FindReconstructionModeProperty() { bool KinectReconstructionMode = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("KinectReconstructionMode",KinectReconstructionMode); if(KinectReconstructionMode) { //set the reconstruction mode for kinect this->m_ToFDistanceImageToSurfaceFilter->SetReconstructionMode(mitk::ToFDistanceImageToSurfaceFilter::Kinect); m_Controls->m_ReconstructionCombobox->setDisabled(true); m_Controls->m_ReconstructionCombobox->setCurrentIndex(2); } else { m_Controls->m_ReconstructionCombobox->setEnabled(true); } } mitk::Surface::Pointer QmitkToFSurfaceGenerationWidget::GetSurface() { return m_Surface; } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp index 4cc09949e7..1a62a732dc 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp @@ -1,133 +1,133 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // mitk core #include #include #include #include #include // mitk gui common plugin #include // namespace that contains the concrete action namespace ReinitAction { void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, const QList& selectedNodes /*= QList()*/, mitk::BaseRenderer* baseRenderer /*= nullptr*/) { if (selectedNodes.empty()) { return; } if (workbenchPartSite.IsNotNull()) { auto renderWindow = mitk::WorkbenchUtil::GetRenderWindowPart(workbenchPartSite->GetPage(), mitk::WorkbenchUtil::NONE); if (nullptr == renderWindow) { renderWindow = mitk::WorkbenchUtil::OpenRenderWindowPart(workbenchPartSite->GetPage(), false); if (nullptr == renderWindow) { // no render window available return; } } } auto boundingBoxPredicate = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false), baseRenderer)); mitk::DataStorage::SetOfObjects::Pointer nodes = mitk::DataStorage::SetOfObjects::New(); for (const auto& dataNode : selectedNodes) { if (boundingBoxPredicate->CheckNode(dataNode)) { nodes->InsertElement(nodes->Size(), dataNode); } } if (nodes->empty()) { return; } if (1 == nodes->Size()) // Special case: If exactly one ... { auto image = dynamic_cast(nodes->ElementAt(0)->GetData()); if (nullptr != image) // ... image is selected, reinit is expected to rectify askew images. { if (nullptr == baseRenderer) { - mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL); + mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry()); } else { - mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), image->GetTimeGeometry(), true); + mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), image->GetTimeGeometry()); } return; } } auto boundingGeometry = dataStorage->ComputeBoundingGeometry3D(nodes, "visible", baseRenderer); if (nullptr == baseRenderer) { mitk::RenderingManager::GetInstance()->InitializeViews(boundingGeometry); } else { mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), boundingGeometry); } } } QmitkDataNodeReinitAction::QmitkDataNodeReinitAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Reinit")); InitializeAction(); } QmitkDataNodeReinitAction::QmitkDataNodeReinitAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Reinit")); InitializeAction(); } void QmitkDataNodeReinitAction::InitializeAction() { connect(this, &QmitkDataNodeReinitAction::triggered, this, &QmitkDataNodeReinitAction::OnActionTriggered); } void QmitkDataNodeReinitAction::OnActionTriggered(bool /*checked*/) { if (m_WorkbenchPartSite.Expired()) { return; } if (m_DataStorage.IsExpired()) { return; } mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); auto selectedNodes = GetSelectedNodes(); ReinitAction::Run(m_WorkbenchPartSite.Lock(), m_DataStorage.Lock(), selectedNodes, baseRenderer); } diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp index 27b424aafd..b9d848b5b6 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp @@ -1,272 +1,271 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkDataManagerView.h" // mitk gui qt datamanager #include "internal/QmitkDataManagerItemDelegate.h" #include "internal/QmitkNodeTableViewKeyFilter.h" // mitk core #include #include #include #include #include #include #include #include #include #include #include #include #include #include // qt widgets module #include #include #include #include #include // beery plugins #include #include #include #include #include #include #include #include #include // mitk core services plugin #include #include // mitk gui common plugin #include #include -#include // mitk gui qt application plugin #include #include // mitk gui qt common plugin #include // qt #include #include #include #include #include const QString QmitkDataManagerView::VIEW_ID = "org.mitk.views.datamanager"; QmitkDataManagerView::QmitkDataManagerView() : m_ItemDelegate(nullptr) { } QmitkDataManagerView::~QmitkDataManagerView() { // nothing here } void QmitkDataManagerView::CreateQtPartControl(QWidget* parent) { m_CurrentRowCount = 0; m_Parent = parent; berry::IBerryPreferences::Pointer prefs = this->GetPreferences().Cast(); assert(prefs); //# GUI m_NodeTreeModel = new QmitkDataStorageTreeModel(GetDataStorage(), prefs->GetBool("Place new nodes on top", true)); m_NodeTreeModel->setParent(parent); m_NodeTreeModel->SetAllowHierarchyChange(prefs->GetBool("Allow changing of parent node", false)); m_SurfaceDecimation = prefs->GetBool("Use surface decimation", false); // Prepare filters m_HelperObjectFilterPredicate = mitk::NodePredicateOr::New( mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)), mitk::NodePredicateProperty::New("hidden object", mitk::BoolProperty::New(true))); m_NodeWithNoDataFilterPredicate = mitk::NodePredicateData::New(nullptr); m_FilterModel = new QmitkDataStorageFilterProxyModel(); m_FilterModel->setSourceModel(m_NodeTreeModel); m_FilterModel->AddFilterPredicate(m_HelperObjectFilterPredicate); m_FilterModel->AddFilterPredicate(m_NodeWithNoDataFilterPredicate); m_NodeTreeView = new QTreeView; m_NodeTreeView->setHeaderHidden(true); m_NodeTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_NodeTreeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_NodeTreeView->setAlternatingRowColors(true); m_NodeTreeView->setDragEnabled(true); m_NodeTreeView->setDropIndicatorShown(true); m_NodeTreeView->setAcceptDrops(true); m_NodeTreeView->setContextMenuPolicy(Qt::CustomContextMenu); m_NodeTreeView->setModel(m_FilterModel); m_NodeTreeView->setTextElideMode(Qt::ElideMiddle); m_NodeTreeView->installEventFilter(new QmitkNodeTableViewKeyFilter(this, GetDataStorage())); m_ItemDelegate = new QmitkDataManagerItemDelegate(m_NodeTreeView); m_NodeTreeView->setItemDelegate(m_ItemDelegate); connect(m_NodeTreeModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)), this, SLOT(NodeTreeViewRowsInserted(const QModelIndex&, int, int))); connect(m_NodeTreeModel, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), this, SLOT(NodeTreeViewRowsRemoved(const QModelIndex&, int, int))); connect(m_NodeTreeView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), this, SLOT(NodeSelectionChanged(const QItemSelection &, const QItemSelection &))); connect(m_NodeTreeModel, &QmitkDataStorageTreeModel::nodeVisibilityChanged, this, &QmitkDataManagerView::OnNodeVisibilityChanged); // data node context menu and menu actions m_DataNodeContextMenu = new QmitkDataNodeContextMenu(GetSite(), m_NodeTreeView); m_DataNodeContextMenu->SetDataStorage(GetDataStorage()); m_DataNodeContextMenu->SetSurfaceDecimation(m_SurfaceDecimation); connect(m_NodeTreeView, SIGNAL(customContextMenuRequested(const QPoint&)), m_DataNodeContextMenu, SLOT(OnContextMenuRequested(const QPoint&))); berry::IEditorRegistry* editorRegistry = berry::PlatformUI::GetWorkbench()->GetEditorRegistry(); QList editors = editorRegistry->GetEditors("*.mitk"); if (editors.size() > 1) { m_ShowInMapper = new QSignalMapper(this); foreach(berry::IEditorDescriptor::Pointer descriptor, editors) { QAction* action = new QAction(descriptor->GetLabel(), this); m_ShowInActions << action; m_ShowInMapper->connect(action, SIGNAL(triggered()), m_ShowInMapper, SLOT(map())); m_ShowInMapper->setMapping(action, descriptor->GetId()); } connect(m_ShowInMapper, SIGNAL(mapped(QString)), this, SLOT(ShowIn(QString))); } QGridLayout* dndFrameWidgetLayout = new QGridLayout; dndFrameWidgetLayout->addWidget(m_NodeTreeView, 0, 0); dndFrameWidgetLayout->setContentsMargins(0, 0, 0, 0); m_DnDFrameWidget = new QmitkDnDFrameWidget(m_Parent); m_DnDFrameWidget->setLayout(dndFrameWidgetLayout); QVBoxLayout* layout = new QVBoxLayout(parent); layout->addWidget(m_DnDFrameWidget); layout->setContentsMargins(0, 0, 0, 0); m_Parent->setLayout(layout); } void QmitkDataManagerView::SetFocus() { } ////////////////////////////////////////////////////////////////////////// // Node tree modification ////////////////////////////////////////////////////////////////////////// void QmitkDataManagerView::NodeTreeViewRowsInserted(const QModelIndex& parent, int /*start*/, int /*end*/) { QModelIndex viewIndex = m_FilterModel->mapFromSource(parent); m_NodeTreeView->setExpanded(viewIndex, true); // a new row was inserted if (m_CurrentRowCount == 0 && m_NodeTreeModel->rowCount() == 1) { mitk::WorkbenchUtil::OpenRenderWindowPart(GetSite()->GetPage()); m_CurrentRowCount = m_NodeTreeModel->rowCount(); } } void QmitkDataManagerView::NodeTreeViewRowsRemoved(const QModelIndex& /*parent*/, int /*start*/, int /*end*/) { m_CurrentRowCount = m_NodeTreeModel->rowCount(); } void QmitkDataManagerView::NodeSelectionChanged(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/) { auto selectedNodes = GetCurrentSelection(); auto nodeSet = m_NodeTreeModel->GetNodeSet(); for (auto node : qAsConst(nodeSet)) { if (node.IsNotNull()) { node->SetSelected(selectedNodes.contains(node)); } } m_DataNodeContextMenu->SetSelectedNodes(selectedNodes); } void QmitkDataManagerView::OnNodeVisibilityChanged() { ToggleVisibilityAction::Run(GetSite(), GetDataStorage(), QList()); } void QmitkDataManagerView::ShowIn(const QString& editorId) { berry::IWorkbenchPage::Pointer page = GetSite()->GetPage(); berry::IEditorInput::Pointer input(new mitk::DataStorageEditorInput(GetDataStorageReference())); page->OpenEditor(input, editorId, false, berry::IWorkbenchPage::MATCH_ID); } void QmitkDataManagerView::NodeChanged(const mitk::DataNode* /*node*/) { // m_FilterModel->invalidate(); // fix as proposed by R. Khlebnikov in the mitk-users mail from 02.09.2014 QMetaObject::invokeMethod(m_FilterModel, "invalidate", Qt::QueuedConnection); } void QmitkDataManagerView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (m_NodeTreeModel->GetPlaceNewNodesOnTopFlag() != prefs->GetBool("Place new nodes on top", true)) { m_NodeTreeModel->SetPlaceNewNodesOnTop(!m_NodeTreeModel->GetPlaceNewNodesOnTopFlag()); } bool hideHelperObjects = !prefs->GetBool("Show helper objects", false); if (m_FilterModel->HasFilterPredicate(m_HelperObjectFilterPredicate) != hideHelperObjects) { if (hideHelperObjects) { m_FilterModel->AddFilterPredicate(m_HelperObjectFilterPredicate); } else { m_FilterModel->RemoveFilterPredicate(m_HelperObjectFilterPredicate); } } bool hideNodesWithNoData = !prefs->GetBool("Show nodes containing no data", false); if (m_FilterModel->HasFilterPredicate(m_NodeWithNoDataFilterPredicate) != hideNodesWithNoData) { if (hideNodesWithNoData) { m_FilterModel->AddFilterPredicate(m_NodeWithNoDataFilterPredicate); } else { m_FilterModel->RemoveFilterPredicate(m_NodeWithNoDataFilterPredicate); } } m_NodeTreeView->expandAll(); m_SurfaceDecimation = prefs->GetBool("Use surface decimation", false); m_DataNodeContextMenu->SetSurfaceDecimation(m_SurfaceDecimation); m_NodeTreeModel->SetAllowHierarchyChange(prefs->GetBool("Allow changing of parent node", false)); GlobalReinitAction::Run(GetSite(), GetDataStorage()); } QItemSelectionModel* QmitkDataManagerView::GetDataNodeSelectionModel() const { return m_NodeTreeView->selectionModel(); } diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.h b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.h index 204f43c841..4570098249 100644 --- a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.h +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.h @@ -1,173 +1,172 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef RTDoseVisualizer_h #define RTDoseVisualizer_h #include #include #include "ui_RTDoseVisualizerControls.h" #include #include #include #include "mitkDoseVisPreferenceHelper.h" // Shader #include #include #include #include -#include #include /*forward declarations*/ class QmitkIsoDoseLevelSetModel; class QmitkDoseColorDelegate; class QmitkDoseValueDelegate; class QmitkDoseVisualStyleDelegate; class ctkEvent; /** \brief RTDoseVisualizer \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkAbstractView \ingroup ${plugin_target}_internal */ class RTDoseVisualizer : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: RTDoseVisualizer(); ~RTDoseVisualizer() override; static const std::string VIEW_ID; static const std::string ISO_LINE_NODE_NAME; void OnSliceChanged(itk::Object *sender, const itk::EventObject &e); protected slots: void OnAddFreeValueClicked(); void OnRemoveFreeValueClicked(); void OnUsePrescribedDoseClicked(); void OnDataChangedInIsoLevelSetView(); void OnAbsDoseToggled(bool); void OnGlobalVisColorWashToggled(bool); void OnGlobalVisIsoLineToggled(bool); void OnShowContextMenuIsoSet(const QPoint&); void OnCurrentPresetChanged(const QString&); void OnReferenceDoseChanged(double); void OnHandleCTKEventReferenceDoseChanged(const ctkEvent& event); void OnHandleCTKEventPresetsChanged(const ctkEvent& event); void OnHandleCTKEventGlobalVisChanged(const ctkEvent& event); void ActualizeFreeIsoLine(); protected: void CreateQtPartControl(QWidget *parent) override; void SetFocus() override; /// \brief called by QmitkFunctionality when DataManager's selection has changed void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, const QList& nodes ) override; void PrepareDoseNode(mitk::DataNode* doseNode) const; /** Update the transfer funtion property for the color wash*/ void UpdateColorWashTransferFunction(); /** Method updates the list widget according to the current free iso values.*/ void UpdateFreeIsoValues(); /** Update the members according to the currently selected node */ void UpdateBySelectedNode(); /** Update the member widgets according to the information stored in the application preferences*/ void UpdateByPreferences(); /**helper function that iterates throug all data nodes and sets there iso level set property according to the selected preset. @TODO: should be moved outside the class, to be available for other classes at well.*/ void ActualizeIsoLevelsForAllDoseDataNodes(); /**helper function that iterates throug all data nodes and sets there reference dose value according to the preference. @TODO: should be moved outside the class, to be available for other classes at well.*/ void ActualizeReferenceDoseForAllDoseDataNodes(); /**helper function that iterates through all data nodes and sets there dose display style (relative/absolute) according to the preference. @TODO: should be moved outside the class, to be available for other classes at well.*/ void ActualizeDisplayStyleForAllDoseDataNodes(); void NodeRemoved(const mitk::DataNode* node) override; void NodeChanged(const mitk::DataNode *node) override; Ui::RTDoseVisualizerControls m_Controls; mitk::DataNode::Pointer m_selectedNode; unsigned int m_freeIsoValuesCount; mitk::PresetMapType m_Presets; std::string m_selectedPresetName; /** Prescribed Dose of the selected data.*/ mitk::DoseValueAbs m_PrescribedDose_Data; QmitkIsoDoseLevelSetModel* m_LevelSetModel; QmitkDoseColorDelegate* m_DoseColorDelegate; QmitkDoseValueDelegate* m_DoseValueDelegate; QmitkDoseVisualStyleDelegate* m_DoseVisualDelegate; bool m_internalUpdate; /**Predicate for dose nodes (excluding iso line nodes)*/ mitk::NodePredicateBase::Pointer m_isDosePredicate; /**Predicate for dose nodes and all iso line nodes*/ mitk::NodePredicateBase::Pointer m_isDoseOrIsoPredicate; /**Predicate for iso line nodes*/ mitk::NodePredicateBase::Pointer m_isIsoPredicate; private: mitk::DataNode::Pointer GetIsoDoseNode(mitk::DataNode::Pointer doseNode) const; }; #endif // RTDoseVisualizer_h diff --git a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp index 2fa229ab9c..4fdc111e1b 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp @@ -1,802 +1,800 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkUSNavigationMarkerPlacement.h" #include "ui_QmitkUSNavigationMarkerPlacement.h" #include "NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h" #include "NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.h" #include "NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.h" #include "SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h" #include "mitkAbstractUltrasoundTrackerDevice.h" #include "mitkIRenderingManager.h" #include "mitkNodeDisplacementFilter.h" #include "mitkTrackedUltrasound.h" #include #include "IO/mitkUSNavigationStepTimer.h" #include #include #include #include #include #include #include "QmitkRenderWindow.h" #include "QmitkStdMultiWidget.h" #include "QmitkStdMultiWidgetEditor.h" #include "mitkCameraController.h" #include "mitkLayoutAnnotationRenderer.h" #include // scene serialization #include #include #include #include #include const std::string QmitkUSNavigationMarkerPlacement::VIEW_ID = "org.mitk.views.usmarkerplacement"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR = "Tumour"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE = "Target Surface"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_ZONES = "Zones"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS = "Targets"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS = "Target Paths"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS = "Reached Targets"; QmitkUSNavigationMarkerPlacement::QmitkUSNavigationMarkerPlacement() : m_Parent(nullptr), m_UpdateTimer(new QTimer(this)), m_ImageAndNavigationDataLoggingTimer(new QTimer(this)), m_StdMultiWidget(nullptr), m_CombinedModality(nullptr), m_ReinitAlreadyDone(false), m_IsExperimentRunning(false), m_CurrentApplicationName(), m_NavigationStepTimer(mitk::USNavigationStepTimer::New()), m_IconRunning(QPixmap(":/USNavigation/record.png")), m_IconNotRunning(QPixmap(":/USNavigation/record-gray.png")), m_ResultsDirectory(), m_ExperimentName(), m_ExperimentResultsSubDirectory(), m_NavigationStepNames(), m_LoggingBackend(), m_USImageLoggingFilter(mitk::USImageLoggingFilter::New()), m_NavigationDataRecorder(mitk::NavigationDataRecorder::New()), m_TargetNodeDisplacementFilter(nullptr), m_AblationZonesDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_ToolVisualizationFilter(nullptr), m_AblationZonesVector(), m_NeedleIndex(0), m_MarkerIndex(1), m_SceneNumber(1), m_WarnOverlay(mitk::TextAnnotation2D::New()), m_NavigationDataSource(nullptr), m_CurrentStorage(nullptr), m_ImageStreamNode(nullptr), ui(new Ui::QmitkUSNavigationMarkerPlacement) { connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(OnTimeout())); connect( m_ImageAndNavigationDataLoggingTimer, SIGNAL(timeout()), this, SLOT(OnImageAndNavigationDataLoggingTimeout())); // scale running (and not running) icon the specific height m_IconRunning = m_IconRunning.scaledToHeight(20, Qt::SmoothTransformation); m_IconNotRunning = m_IconNotRunning.scaledToHeight(20, Qt::SmoothTransformation); } QmitkUSNavigationMarkerPlacement::~QmitkUSNavigationMarkerPlacement() { this->GetDataStorage()->Remove(m_InstrumentNode); delete ui; } void QmitkUSNavigationMarkerPlacement::OnChangeAblationZone(int id, int newSize) { if ((static_cast(m_AblationZonesVector.size()) < id) || (id < 0)) { return; } MITK_INFO << "Ablation Zone " << id << " changed, new size: " << newSize; // create a vtk sphere with given radius vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(newSize / 2); vtkSphere->SetCenter(0, 0, 0); vtkSphere->SetPhiResolution(20); vtkSphere->SetThetaResolution(20); vtkSphere->Update(); mitk::Surface::Pointer zoneSurface = dynamic_cast(m_AblationZonesVector.at(id)->GetData()); zoneSurface->SetVtkPolyData(vtkSphere->GetOutput()); } void QmitkUSNavigationMarkerPlacement::OnAddAblationZone(int size) { m_AblationZonesDisplacementFilter->SetInitialReferencePose( m_CombinedModality->GetNavigationDataSource()->GetOutput(m_MarkerIndex)); mitk::DataNode::Pointer NewAblationZone = mitk::DataNode::New(); mitk::Point3D origin = m_CombinedModality->GetNavigationDataSource()->GetOutput(m_NeedleIndex)->GetPosition(); MITK_INFO("USNavigationLogging") << "Ablation Zone Added, initial size: " << size << ", origin: " << origin; mitk::Surface::Pointer zone = mitk::Surface::New(); // create a vtk sphere with given radius vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(size / 2); vtkSphere->SetCenter(0, 0, 0); vtkSphere->SetPhiResolution(20); vtkSphere->SetThetaResolution(20); vtkSphere->Update(); zone->SetVtkPolyData(vtkSphere->GetOutput()); // set vtk sphere and origin to data node (origin must be set // again, because of the new sphere set as data) NewAblationZone->SetData(zone); NewAblationZone->GetData()->GetGeometry()->SetOrigin(origin); mitk::Color SphereColor = mitk::Color(); // default color SphereColor[0] = 102; SphereColor[1] = 0; SphereColor[2] = 204; NewAblationZone->SetColor(SphereColor); NewAblationZone->SetOpacity(0.3); // set name of zone std::stringstream name; name << "Ablation Zone" << m_AblationZonesVector.size(); NewAblationZone->SetName(name.str()); // add zone to filter m_AblationZonesDisplacementFilter->AddNode(NewAblationZone); m_AblationZonesVector.push_back(NewAblationZone); this->GetDataStorage()->Add(NewAblationZone); } void QmitkUSNavigationMarkerPlacement::CreateQtPartControl(QWidget *parent) { m_Parent = parent; ui->setupUi(parent); connect(ui->startExperimentButton, SIGNAL(clicked()), this, SLOT(OnStartExperiment())); connect(ui->finishExperimentButton, SIGNAL(clicked()), this, SLOT(OnFinishExperiment())); connect(ui->m_enableNavigationLayout, SIGNAL(clicked()), this, SLOT(OnChangeLayoutClicked())); connect(ui->m_RenderWindowSelection, SIGNAL(valueChanged(int)), this, SLOT(OnRenderWindowSelection())); connect(ui->m_RefreshView, SIGNAL(clicked()), this, SLOT(OnRefreshView())); m_BaseNode = this->GetDataStorage()->GetNamedNode(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (m_BaseNode.IsNull()) { m_BaseNode = mitk::DataNode::New(); m_BaseNode->SetName(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); this->GetDataStorage()->Add(m_BaseNode); } connect(ui->m_CtToUsRegistrationWidget, SIGNAL(GetCursorPosition()), this, SLOT(OnGetCursorPosition())); connect(ui->m_CtToUsRegistrationWidget, SIGNAL(ActualizeCtToUsRegistrationWidget()), this, SLOT(OnActualizeCtToUsRegistrationWidget())); connect(ui->m_initializeCtToUsRegistration, SIGNAL(clicked()), this, SLOT(OnInitializeCtToUsRegistration())); connect(ui->m_initializeTargetMarking, SIGNAL(clicked()), this, SLOT(OnInitializeTargetMarking())); connect(ui->m_initializeCritStructureMarking, SIGNAL(clicked()), this, SLOT(OnInitializeCriticalStructureMarking())); connect(ui->m_initializeNavigation, SIGNAL(clicked()), this, SLOT(OnInitializeNavigation())); // indicate that no experiment is running at start ui->runningLabel->setPixmap(m_IconNotRunning); connect(ui->m_settingsWidget, SIGNAL(SettingsChanged(itk::SmartPointer)), this, SLOT(OnSettingsChanged(itk::SmartPointer))); } void QmitkUSNavigationMarkerPlacement::ReInitializeSettingsNodesAndImageStream() { //If update timer is not stopped (signals stopped), setting the m_CombinedModality // will cause a crash of the workbench in some times. m_UpdateTimer->blockSignals(true); m_UpdateTimer->stop(); m_SettingsNode = mitk::DataNode::New(); ui->m_settingsWidget->OnSetSettingsNode(m_SettingsNode, true); InitImageStream(); m_CombinedModality = ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality(); // Having set the m_CombinedModality reactivate the update timer again m_UpdateTimer->start(50); // every 50 Milliseconds = 20 Frames/Second m_UpdateTimer->blockSignals(false); } void QmitkUSNavigationMarkerPlacement::OnGetCursorPosition() { auto centroid = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetSelectedPosition(); ui->m_CtToUsRegistrationWidget->OnCalculateTRE(centroid); } void QmitkUSNavigationMarkerPlacement::OnActualizeCtToUsRegistrationWidget() { m_SettingsNode = mitk::DataNode::New(); ui->m_settingsWidget->OnSetSettingsNode(m_SettingsNode, true); this->InitImageStream(); if (ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality().IsNull()) { return; } ui->m_CtToUsRegistrationWidget->SetCombinedModality( ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality()); m_CombinedModality = ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality(); if (!m_StdMultiWidget) { // try to get the standard multi widget if it couldn't be got before mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindowPart); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { m_StdMultiWidget = dynamic_cast(multiWidgetEditor->GetMultiWidget()); multiWidgetEditor->ShowLevelWindowWidget(false); SetTwoWindowView(); } } else { this->OnRefreshView(); } m_UpdateTimer->start(50); // every 50 Milliseconds = 20 Frames/Second } void QmitkUSNavigationMarkerPlacement::OnInitializeCtToUsRegistration() { ui->m_CtToUsRegistrationWidget->SetDataStorage(this->GetDataStorage()); ui->m_CtToUsRegistrationWidget->OnSettingsChanged(m_SettingsNode); ui->m_CtToUsRegistrationWidget->OnActivateStep(); ui->m_CtToUsRegistrationWidget->OnStartStep(); ui->m_CtToUsRegistrationWidget->Update(); } void QmitkUSNavigationMarkerPlacement::OnInitializeTargetMarking() { ReInitializeSettingsNodesAndImageStream(); ui->m_TargetMarkingWidget->SetCombinedModality(m_CombinedModality); ui->m_TargetMarkingWidget->SetDataStorage(this->GetDataStorage()); ui->m_TargetMarkingWidget->OnSettingsChanged(m_SettingsNode); ui->m_TargetMarkingWidget->OnActivateStep(); ui->m_TargetMarkingWidget->OnStartStep(); ui->m_TargetMarkingWidget->Update(); } void QmitkUSNavigationMarkerPlacement::OnInitializeCriticalStructureMarking() { ReInitializeSettingsNodesAndImageStream(); ui->m_CriticalStructuresWidget->SetCombinedModality(m_CombinedModality); ui->m_CriticalStructuresWidget->SetDataStorage(this->GetDataStorage()); ui->m_CriticalStructuresWidget->OnSettingsChanged(m_SettingsNode); ui->m_CriticalStructuresWidget->OnActivateStep(); ui->m_CriticalStructuresWidget->OnStartStep(); ui->m_CriticalStructuresWidget->Update(); } void QmitkUSNavigationMarkerPlacement::OnInitializeNavigation() { ReInitializeSettingsNodesAndImageStream(); ui->m_NavigationWidget->SetCombinedModality(m_CombinedModality); ui->m_NavigationWidget->SetDataStorage(this->GetDataStorage()); ui->m_NavigationWidget->OnSettingsChanged(m_SettingsNode); ui->m_NavigationWidget->OnActivateStep(); ui->m_NavigationWidget->OnStartStep(); ui->m_NavigationWidget->Update(); // test if it is tracked US, if yes add visualization filter if (m_CombinedModality->GetIsTrackedUltrasoundActive()) { m_InstrumentNode = mitk::DataNode::New(); m_InstrumentNode->SetName("Tracked US Instrument"); m_InstrumentNode->SetData( m_CombinedModality->GetNavigationDataSource()->GetToolMetaData(0)->GetToolSurface()->Clone()); this->GetDataStorage()->Add(m_InstrumentNode); m_ToolVisualizationFilter = mitk::NavigationDataObjectVisualizationFilter::New(); m_ToolVisualizationFilter->ConnectTo(m_CombinedModality->GetNavigationDataSource()); m_ToolVisualizationFilter->SetRepresentationObject(0, m_InstrumentNode->GetData()); //caution: currently hard coded that instrument has id 0 //set dummy objects to avoid spamming of console mitk::Surface::Pointer dummyObject = mitk::Surface::New(); m_ToolVisualizationFilter->SetRepresentationObject(1, dummyObject.GetPointer()); m_ToolVisualizationFilter->SetRepresentationObject(2, dummyObject.GetPointer()); } } void QmitkUSNavigationMarkerPlacement::InitImageStream() { if (m_ImageStreamNode.IsNull()) { m_ImageStreamNode = mitk::DataNode::New(); m_ImageStreamNode->SetName("US Navigation Viewing Stream"); this->GetDataStorage()->Add(m_ImageStreamNode); } } void QmitkUSNavigationMarkerPlacement::OnCombinedModalityPropertyChanged(const std::string &key, const std::string &) { if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { m_ReinitAlreadyDone = false; this->ReinitOnImage(); if (m_CombinedModality.IsNotNull() && !m_CombinedModality->GetIsCalibratedForCurrentStatus()) { mitk::LayoutAnnotationRenderer::AddAnnotation( m_WarnOverlay.GetPointer(), "stdmulti.widget0", mitk::LayoutAnnotationRenderer::TopLeft); MITK_WARN << "No calibration available for the selected ultrasound image depth."; } } } void QmitkUSNavigationMarkerPlacement::SetFocus() { this->ReinitOnImage(); } void QmitkUSNavigationMarkerPlacement::OnTimeout() { if (m_CombinedModality.IsNull()) return; m_CombinedModality->Modified(); // shouldn't be nessecary ... fix in abstract ultrasound tracker device! m_CombinedModality->Update(); if (m_ToolVisualizationFilter.IsNotNull()) { m_ToolVisualizationFilter->Update(); } ui->m_CtToUsRegistrationWidget->Update(); ui->m_TargetMarkingWidget->Update(); ui->m_CriticalStructuresWidget->Update(); ui->m_NavigationWidget->Update(); mitk::Image::Pointer image = m_CombinedModality->GetOutput(); // make sure that always the current image is set to the data node if (image.IsNotNull() && m_ImageStreamNode->GetData() != image.GetPointer() && image->IsInitialized()) { m_ImageStreamNode->SetData(image); } if (!m_StdMultiWidget) { // try to get the standard multi widget if it couldn't be got before mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindowPart); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { m_StdMultiWidget = dynamic_cast(multiWidgetEditor->GetMultiWidget()); multiWidgetEditor->ShowLevelWindowWidget(false); SetTwoWindowView(); } this->CreateOverlays(); } if (m_CombinedModality.IsNotNull() && !this->m_CombinedModality->GetIsFreezed()) // if the combined modality is freezed: do nothing { m_AblationZonesDisplacementFilter->Update(); // update the 3D window only every fourth time to speed up the rendering (at least in 2D) this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); // make sure that a reinit was performed on the image this->ReinitOnImage(); } } void QmitkUSNavigationMarkerPlacement::OnEnableNavigationLayout() { MITK_INFO << "Navigation Layout"; // try to get the standard multi widget if it couldn't be got before mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindowPart); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { m_StdMultiWidget = dynamic_cast(multiWidgetEditor->GetMultiWidget()); multiWidgetEditor->ShowLevelWindowWidget(false); SetTwoWindowView(); } } void QmitkUSNavigationMarkerPlacement::OnRenderWindowSelection() { SetTwoWindowView(); } void QmitkUSNavigationMarkerPlacement::OnRefreshView() { if (!ui->m_enableNavigationLayout->isChecked()) OnResetStandardLayout(); else { // Reinit the US Image Stream (this might be broken if there was a global reinit somewhere...) try { mitk::RenderingManager::GetInstance()->InitializeViews( // Reinit this ->GetDataStorage() // GetDataStorage ->GetNamedNode("US Viewing Stream - Image 0") ->GetData() ->GetTimeGeometry()); // GetNode } catch (...) { MITK_DEBUG << "No reinit possible"; } SetTwoWindowView(); } } void QmitkUSNavigationMarkerPlacement::SetTwoWindowView() { if (m_StdMultiWidget) { int i, j, k; switch (this->ui->m_RenderWindowSelection->value()) { case 1: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))->GetCameraController()->SetViewToCaudal(); i = 1; j = 2; // other windows k = 0; break; case 2: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))->GetCameraController()->SetViewToSinister(); i = 0; j = 2; k = 1; break; case 3: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))->GetCameraController()->SetViewToAnterior(); i = 1; j = 0; k = 2; break; default: return; } // get the render window which is defined by index "k" and set it as "current render window widget" // chose the layout that will set the current 2D window as top render window and the 3D windows as bottom render window auto renderWindowWidget = m_StdMultiWidget->GetRenderWindowWidget(m_StdMultiWidget->GetNameFromIndex(k)); m_StdMultiWidget->GetMultiWidgetLayoutManager()->SetCurrentRenderWindowWidget(renderWindowWidget.get()); m_StdMultiWidget->GetMultiWidgetLayoutManager()->SetOneTop3DBottomLayout(); ////Crosshair invisible in 3D view this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane") ->SetBoolProperty("visible", false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane") ->SetBoolProperty("visible", false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(k) + ".plane") ->SetBoolProperty("visible", true, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane") ->SetIntProperty("Crosshair.Gap Size", 0); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane") ->SetIntProperty("Crosshair.Gap Size", 0); } } void QmitkUSNavigationMarkerPlacement::OnResetStandardLayout() { if (m_StdMultiWidget) { //reset render windows m_StdMultiWidget->SetCrosshairVisibility(true); m_StdMultiWidget->GetMultiWidgetLayoutManager()->SetDefaultLayout(); } } void QmitkUSNavigationMarkerPlacement::OnChangeLayoutClicked() { if (ui->m_enableNavigationLayout->isChecked()) OnEnableNavigationLayout(); else OnResetStandardLayout(); } void QmitkUSNavigationMarkerPlacement::OnImageAndNavigationDataLoggingTimeout() { // update filter for logging navigation data and ultrasound images if (m_CombinedModality.IsNotNull()) { m_NavigationDataRecorder->Update(); // get last messages for logging filer and store them std::vector messages = m_LoggingBackend.GetNavigationMessages(); std::string composedMessage = ""; for (std::size_t i = 0; i < messages.size(); i++) { composedMessage += messages.at(i); } m_USImageLoggingFilter->AddMessageToCurrentImage(composedMessage); m_LoggingBackend.ClearNavigationMessages(); // update logging filter m_USImageLoggingFilter->Update(); } } void QmitkUSNavigationMarkerPlacement::OnStartExperiment() { // get name for the experiment by a QInputDialog bool ok; if (m_ExperimentName.isEmpty()) { // default: current date m_ExperimentName = QString::number(QDateTime::currentDateTime().date().year()) + "_" + QString::number(QDateTime::currentDateTime().date().month()) + "_" + QString::number(QDateTime::currentDateTime().date().day()) + "_experiment_" + QString::number(QDateTime::currentDateTime().time().hour()) + "." + QString::number(QDateTime::currentDateTime().time().minute()); } m_ExperimentName = QInputDialog::getText( m_Parent, QString("Experiment Name"), QString("Name of the Experiment"), QLineEdit::Normal, m_ExperimentName, &ok); MITK_INFO("USNavigationLogging") << "Experiment started: " << m_ExperimentName.toStdString(); if (ok && !m_ExperimentName.isEmpty()) { // display error message and call the function recursively if a directory // with the given name already exists QDir experimentResultsDir(m_ResultsDirectory + QDir::separator() + m_ExperimentName); if (experimentResultsDir.exists()) { QMessageBox::critical( m_Parent, "Results Directory Exists", "The result directory already exists.\nPlease choose an other name."); this->OnStartExperiment(); } else { QDir(m_ResultsDirectory).mkdir(m_ExperimentName); m_ExperimentResultsSubDirectory = m_ResultsDirectory + QDir::separator() + m_ExperimentName; // experiment is running now ui->runningLabel->setPixmap(m_IconRunning); // (re)start timer for navigation step durations m_NavigationStepTimer->Reset(); m_NavigationStepTimer->SetOutputFileName( QString(m_ExperimentResultsSubDirectory + QDir::separator() + QString("durations.cvs")).toStdString()); m_NavigationStepTimer->SetActiveIndex(0, "Initialization"); ui->finishExperimentButton->setEnabled(true); ui->startExperimentButton->setDisabled(true); // initialize and register logging backend QString loggingFilename = m_ExperimentResultsSubDirectory + QDir::separator() + "logging.txt"; m_LoggingBackend.SetOutputFileName(loggingFilename.toStdString()); mbilog::RegisterBackend(&m_LoggingBackend); // initialize and start navigation data recorder form xml recording m_NavigationDataRecorder->StartRecording(); m_IsExperimentRunning = true; m_ImageAndNavigationDataLoggingTimer->start(1000); } } } void QmitkUSNavigationMarkerPlacement::OnFinishExperiment() { this->WaitCursorOn(); MITK_INFO("USNavigationLogging") << "Experiment finished!"; MITK_INFO("USNavigationLogging") << "Position/Orientation of needle tip: " << (dynamic_cast( m_CombinedModality->GetTrackingDeviceDataSource()->GetOutput(0))) ->GetPosition(); MITK_INFO("USNavigationLogging") << "Position of target: " << m_TargetNodeDisplacementFilter->GetRawDisplacementNavigationData(0)->GetPosition(); MITK_INFO("USNavigationLogging") << "Total duration: " << m_NavigationStepTimer->GetTotalDuration(); m_ImageAndNavigationDataLoggingTimer->stop(); ui->runningLabel->setPixmap(m_IconNotRunning); m_NavigationStepTimer->Stop(); ui->finishExperimentButton->setDisabled(true); ui->startExperimentButton->setEnabled(true); MITK_INFO("USNavigationLogging") << "Writing logging data to " << m_ExperimentResultsSubDirectory.toStdString(); // save ultrasound images to the file system QDir(m_ExperimentResultsSubDirectory).mkdir("ImageStream"); m_USImageLoggingFilter->Update(); m_USImageLoggingFilter->SetImageFilesExtension(".jpg"); m_USImageLoggingFilter->SaveImages( QString(m_ExperimentResultsSubDirectory + QDir::separator() + "ImageStream" + QDir::separator()).toStdString()); m_USImageLoggingFilter = mitk::USImageLoggingFilter::New(); m_NavigationDataRecorder->StopRecording(); // Write data to csv and xml file mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.xml").toStdString().c_str())); mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.csv").toStdString().c_str())); // write logged navigation data messages to separate file std::stringstream csvNavigationMessagesFilename; csvNavigationMessagesFilename << m_ExperimentResultsSubDirectory.toStdString() << QDir::separator().toLatin1() << "CSVNavigationMessagesLogFile.csv"; MITK_INFO("USNavigationLogging") << "Writing logged navigation messages to separate csv file: " << csvNavigationMessagesFilename.str(); m_LoggingBackend.WriteCSVFileWithNavigationMessages(csvNavigationMessagesFilename.str()); mbilog::UnregisterBackend(&m_LoggingBackend); m_IsExperimentRunning = false; m_ImageAndNavigationDataLoggingTimer->stop(); m_CombinedModality = nullptr; // reset scene number for next experiment m_SceneNumber = 1; this->WaitCursorOff(); MITK_INFO("USNavigationLogging") << "Finished!"; } void QmitkUSNavigationMarkerPlacement::OnSettingsChanged(itk::SmartPointer settings) { // initialize gui according to the experiment mode setting bool experimentMode = false; settings->GetBoolProperty("settings.experiment-mode", experimentMode); ui->startExperimentButton->setVisible(experimentMode); ui->finishExperimentButton->setVisible(experimentMode); ui->runningLabel->setVisible(experimentMode); if (experimentMode && !m_IsExperimentRunning) { ui->runningLabel->setPixmap(m_IconNotRunning); } else if (!experimentMode) { if (m_IsExperimentRunning) { this->OnFinishExperiment(); } } // get the results directory from the settings and use home directory if // there is no results directory configured std::string resultsDirectory; if (settings->GetStringProperty("settings.experiment-results-directory", resultsDirectory)) { m_ResultsDirectory = QString::fromStdString(resultsDirectory); } else { m_ResultsDirectory = QDir::homePath(); } // make sure that the results directory exists QDir resultsDirectoryQDir = QDir(m_ResultsDirectory); if (!resultsDirectoryQDir.exists()) { resultsDirectoryQDir.mkpath(m_ResultsDirectory); } MITK_INFO("USNavigation") << "Results Directory: " << m_ResultsDirectory.toStdString(); } void QmitkUSNavigationMarkerPlacement::ReinitOnImage() { if (!m_ReinitAlreadyDone && m_CombinedModality.IsNotNull()) { // make sure that the output is already calibrated correctly // (if the zoom level was changed recently) m_CombinedModality->Modified(); m_CombinedModality->Update(); mitk::Image::Pointer image = m_CombinedModality->GetOutput(); if (image.IsNotNull() && image->IsInitialized()) { // make a reinit on the ultrasound image mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); if (renderWindowPart != nullptr && image->GetTimeGeometry()->IsValid()) { - renderWindowPart->GetRenderingManager()->InitializeViews( - image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - renderWindowPart->GetRenderingManager()->RequestUpdateAll(); + renderWindowPart->GetRenderingManager()->InitializeViews(image->GetTimeGeometry()); } this->RequestRenderWindowUpdate(); m_ReinitAlreadyDone = true; } } } void QmitkUSNavigationMarkerPlacement::Convert2DImagesTo3D(mitk::DataStorage::SetOfObjects::ConstPointer nodes) { for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); ++it) { if (it->Value()->GetData() && strcmp(it->Value()->GetData()->GetNameOfClass(), "Image") == 0) { // convert image to 3d image if it is 2d at the moment mitk::Image::Pointer image = dynamic_cast(it->Value()->GetData()); if (image.IsNotNull() && image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable()) { mitk::Convert2Dto3DImageFilter::Pointer convert2DTo3DImageFilter = mitk::Convert2Dto3DImageFilter::New(); convert2DTo3DImageFilter->SetInput(image); convert2DTo3DImageFilter->Update(); it->Value()->SetData(convert2DTo3DImageFilter->GetOutput()); } } } } void QmitkUSNavigationMarkerPlacement::CreateOverlays() { // initialize warning overlay (and do not display it, yet) m_WarnOverlay->SetText("Warning: No calibration available for current depth."); // set position and font size for the text overlay // (nonesense postition as a layouter is used, but it ignored // the overlay without setting a position here) mitk::Point2D overlayPosition; overlayPosition.SetElement(0, -50.0f); overlayPosition.SetElement(1, -50.0f); m_WarnOverlay->SetPosition2D(overlayPosition); m_WarnOverlay->SetFontSize(22); m_WarnOverlay->SetColor(1, 0, 0); // overlay should be red } void QmitkUSNavigationMarkerPlacement::UpdateToolStorage() { if (m_NavigationDataSource.IsNull()) { m_NavigationDataSource = m_CombinedModality->GetNavigationDataSource(); } if (m_NavigationDataSource.IsNull()) { MITK_WARN << "Found an invalid navigation data source object!"; } us::ModuleContext *context = us::GetModuleContext(); std::string id = m_NavigationDataSource->US_PROPKEY_ID; std::string filter = "(" + mitk::NavigationToolStorage::US_PROPKEY_SOURCE_ID + "=" + id + ")"; // Get Storage std::vector> refs = context->GetServiceReferences(); m_CurrentStorage = context->GetService(refs.front()); if (m_CurrentStorage.IsNull()) { MITK_WARN << "Found an invalid storage object!"; } else if (m_CurrentStorage->GetToolCount() != m_NavigationDataSource->GetNumberOfOutputs()) // there is something wrong with the storage { MITK_WARN << "Found a tool storage, but it has not the same number of tools like the NavigationDataSource. This " "storage won't be used because it isn't the right one."; m_CurrentStorage = nullptr; } } diff --git a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUltrasoundCalibration.cpp b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUltrasoundCalibration.cpp index 3134d15837..01c5869c50 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUltrasoundCalibration.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUltrasoundCalibration.cpp @@ -1,1398 +1,1397 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkUltrasoundCalibration.h" #include // Qt #include #include #include #include // MITK #include #include "mitkIOUtil.h" -#include "mitkIRenderingManager.h" #include #include #include #include #include #include #include #include #include // us #include // VTK #include #include #include #include #include #include #include #include "internal/org_mbi_gui_qt_usnavigation_Activator.h" // sleep headers #include #include const std::string QmitkUltrasoundCalibration::VIEW_ID = "org.mitk.views.ultrasoundcalibration"; QmitkUltrasoundCalibration::QmitkUltrasoundCalibration() : m_PhantomConfigurationPointSet(nullptr), m_USDeviceChanged(this, &QmitkUltrasoundCalibration::OnUSDepthChanged) { ctkPluginContext *pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { // to be notified about service event of an USDevice pluginContext->connectServiceListener(this, "OnDeviceServiceEvent", QString::fromStdString("(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")")); } } QmitkUltrasoundCalibration::~QmitkUltrasoundCalibration() { m_Controls.m_CombinedModalityManagerWidget->blockSignals(true); mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality; combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { combinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_USDeviceChanged); } m_Timer->stop(); this->OnStopCalibrationProcess(); this->OnStopPlusCalibration(); mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Needle Path"); if (node.IsNotNull()) this->GetDataStorage()->Remove(node); this->GetDataStorage()->Remove(m_VerificationReferencePointsDataNode); delete m_Timer; // remove observer for phantom-based point adding m_CalibPointsImage->RemoveAllObservers(); } void QmitkUltrasoundCalibration::SetFocus() { m_Controls.m_ToolBox->setFocus(); } void QmitkUltrasoundCalibration::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Controls.m_CombinedModalityManagerWidget->SetCalibrationLoadedNecessary(false); m_Timer = new QTimer(this); m_StreamingTimer = new QTimer(this); m_Controls.m_SpacingBtnFreeze->setEnabled(true); m_Controls.m_SpacingAddPoint->setEnabled(false); m_Controls.m_CalculateSpacing->setEnabled(false); m_SpacingPointsCount = 0; m_SpacingPoints = mitk::PointSet::New(); m_SpacingNode = mitk::DataNode::New(); m_SpacingNode->SetName("Spacing Points"); m_SpacingNode->SetData(this->m_SpacingPoints); this->GetDataStorage()->Add(m_SpacingNode); // Pointset for Calibration Points m_CalibPointsTool = mitk::PointSet::New(); // Pointset for Worldpoints m_CalibPointsImage = mitk::PointSet::New(); m_CalibPointsCount = 0; // Evaluation Pointsets (Non-Visualized) m_EvalPointsImage = mitk::PointSet::New(); m_EvalPointsTool = mitk::PointSet::New(); m_EvalPointsProjected = mitk::PointSet::New(); // Neelde Projection Filter m_NeedleProjectionFilter = mitk::NeedleProjectionFilter::New(); // Tracking Status Widgets m_Controls.m_CalibTrackingStatus->ShowStatusLabels(); m_Controls.m_EvalTrackingStatus->ShowStatusLabels(); // General & Device Selection connect(m_Timer, SIGNAL(timeout()), this, SLOT(Update())); // Calibration connect(m_Controls.m_CalibBtnFreeze, SIGNAL(clicked()), this, SLOT(SwitchFreeze())); // Freeze connect(m_Controls.m_CalibBtnAddPoint, SIGNAL(clicked()), this, SLOT(OnAddCalibPoint())); // Tracking & Image Points (Calibration) connect(m_Controls.m_CalibBtnCalibrate, SIGNAL(clicked()), this, SLOT(OnCalibration())); // Perform Calibration // Phantom-based calibration connect(m_Controls.m_CalibBtnLoadPhantomConfiguration, SIGNAL(clicked()), this, SLOT(OnLoadPhantomConfiguration())); // Phantom configuration connect(m_Controls.m_CalibBtnMatchAnnotationToPhantomConfiguration, SIGNAL(clicked()), this, SLOT(OnMatchAnnotationToPhantomConfiguration())); connect(m_Controls.m_CalibBtnMoveUp, SIGNAL(clicked()), this, SLOT(OnMovePhantomAnnotationsUp())); connect(m_Controls.m_CalibBtnMoveDown, SIGNAL(clicked()), this, SLOT(OnMovePhantomAnnotationsDown())); connect(m_Controls.m_CalibBtnMoveLeft, SIGNAL(clicked()), this, SLOT(OnMovePhantomAnnotationsLeft())); connect(m_Controls.m_CalibBtnMoveRight, SIGNAL(clicked()), this, SLOT(OnMovePhantomAnnotationsRight())); connect(m_Controls.m_CalibBtnRotateRight, SIGNAL(clicked()), this, SLOT(OnRotatePhantomAnnotationsRight())); connect(m_Controls.m_CalibBtnRotateLeft, SIGNAL(clicked()), this, SLOT(OnRotatePhantomAnnotationsLeft())); connect(m_Controls.m_CalibBtnPerformPhantomCalibration, SIGNAL(clicked()), this, SLOT(OnPhantomBasedCalibration())); // Perform phantom-based calibration connect(m_Controls.m_CalibBtnSavePhantomCalibration, SIGNAL(clicked()), this, SLOT(OnSaveCalibration())); // Save phantom-based calibration // Evaluation connect(m_Controls.m_EvalBtnStep1, SIGNAL(clicked()), this, SLOT(OnAddEvalProjectedPoint())); // Needle Projection connect(m_Controls.m_EvalBtnStep2, SIGNAL(clicked()), this, SLOT(SwitchFreeze())); // Freeze connect(m_Controls.m_EvalBtnStep3, SIGNAL(clicked()), this, SLOT(OnAddEvalTargetPoint())); // Tracking & Image Points (Evaluation) connect(m_Controls.m_EvalBtnSave, SIGNAL(clicked()), this, SLOT(OnSaveEvaluation())); // Save Evaluation Results connect(m_Controls.m_CalibBtnSaveCalibration, SIGNAL(clicked()), this, SLOT(OnSaveCalibration())); // Save Evaluation Results connect(m_Controls.m_BtnReset, SIGNAL(clicked()), this, SLOT(OnReset())); // Reset Pointsets // PLUS Calibration connect(m_Controls.m_GetCalibrationFromPLUS, SIGNAL(clicked()), this, SLOT(OnGetPlusCalibration())); connect(m_Controls.m_StartStreaming, SIGNAL(clicked()), this, SLOT(OnStartStreaming())); connect(m_StreamingTimer, SIGNAL(timeout()), this, SLOT(OnStreamingTimerTimeout())); connect(m_Controls.m_StopPlusCalibration, SIGNAL(clicked()), this, SLOT(OnStopPlusCalibration())); connect(m_Controls.m_SavePlusCalibration, SIGNAL(clicked()), this, SLOT(OnSaveCalibration())); connect(this, SIGNAL(NewConnectionSignal()), this, SLOT(OnNewConnection())); // Determine Spacing for Calibration of USVideoDevice connect(m_Controls.m_SpacingBtnFreeze, SIGNAL(clicked()), this, SLOT(OnFreezeClicked())); connect(m_Controls.m_SpacingAddPoint, SIGNAL(clicked()), this, SLOT(OnAddSpacingPoint())); connect(m_Controls.m_CalculateSpacing, SIGNAL(clicked()), this, SLOT(OnCalculateSpacing())); connect(m_Controls.m_CombinedModalityManagerWidget, SIGNAL(SignalReadyForNextStep()), this, SLOT(OnDeviceSelected())); connect(m_Controls.m_CombinedModalityManagerWidget, SIGNAL(SignalNoLongerReadyForNextStep()), this, SLOT(OnDeviceDeselected())); connect(m_Controls.m_StartCalibrationButton, SIGNAL(clicked()), this, SLOT(OnStartCalibrationProcess())); connect(m_Controls.m_StartPlusCalibrationButton, SIGNAL(clicked()), this, SLOT(OnStartPlusCalibration())); connect(m_Controls.m_CalibBtnRestartCalibration, SIGNAL(clicked()), this, SLOT(OnReset())); connect(m_Controls.m_CalibBtnStopCalibration, SIGNAL(clicked()), this, SLOT(OnStopCalibrationProcess())); connect(m_Controls.m_AddReferencePoints, SIGNAL(clicked()), this, SLOT(OnAddCurrentTipPositionToReferencePoints())); connect(m_Controls.m_AddCurrentPointerTipForVerification, SIGNAL(clicked()), this, SLOT(OnAddCurrentTipPositionForVerification())); connect(m_Controls.m_StartVerification, SIGNAL(clicked()), this, SLOT(OnStartVerification())); // initialize data storage combo box m_Controls.m_ReferencePointsComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_ReferencePointsComboBox->SetAutoSelectNewItems(true); m_Controls.m_ReferencePointsComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); // initialize point list widget if (m_VerificationReferencePoints.IsNull()) { m_VerificationReferencePoints = mitk::PointSet::New(); } if (m_VerificationReferencePointsDataNode.IsNull()) { m_VerificationReferencePointsDataNode = mitk::DataNode::New(); m_VerificationReferencePointsDataNode->SetName("US Verification Reference Points"); m_VerificationReferencePointsDataNode->SetData(m_VerificationReferencePoints); this->GetDataStorage()->Add(m_VerificationReferencePointsDataNode); } m_Controls.m_ReferencePointsPointListWidget->SetPointSetNode(m_VerificationReferencePointsDataNode); m_Controls.m_ToolBox->setCurrentIndex(0); } void QmitkUltrasoundCalibration::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList & /*nodes*/) { } void QmitkUltrasoundCalibration::OnTabSwitch(int index) { switch (index) { case 0: if (m_Controls.m_ToolBox->isItemEnabled(1) || m_Controls.m_ToolBox->isItemEnabled(2)) { this->OnStopCalibrationProcess(); } break; default:; } } void QmitkUltrasoundCalibration::OnDeviceSelected() { mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality; combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { combinedModality->GetUltrasoundDevice()->AddPropertyChangedListener(m_USDeviceChanged); m_Controls.m_StartCalibrationButton->setEnabled(true); m_Controls.m_StartPlusCalibrationButton->setEnabled(true); m_Controls.m_ToolBox->setItemEnabled(1, true); m_Controls.m_ToolBox->setItemEnabled(2, true); } } void QmitkUltrasoundCalibration::OnDeviceDeselected() { mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality; combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { combinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_USDeviceChanged); } m_Controls.m_StartCalibrationButton->setEnabled(false); m_Controls.m_StartPlusCalibrationButton->setEnabled(false); m_Controls.m_ToolBox->setCurrentIndex(0); m_Controls.m_ToolBox->setItemEnabled(1, false); m_Controls.m_ToolBox->setItemEnabled(2, false); } void QmitkUltrasoundCalibration::OnAddCurrentTipPositionToReferencePoints() { if (m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource().IsNull() || (m_Controls.m_VerificationPointerChoser->GetSelectedToolID() == -1)) { MITK_WARN << "No tool selected, aborting"; return; } mitk::NavigationData::Pointer currentPointerData = m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource()->GetOutput( m_Controls.m_VerificationPointerChoser->GetSelectedToolID()); mitk::Point3D currentTipPosition = currentPointerData->GetPosition(); m_VerificationReferencePoints->InsertPoint(m_VerificationReferencePoints->GetSize(), currentTipPosition); } void QmitkUltrasoundCalibration::OnStartVerification() { m_currentPoint = 0; mitk::PointSet::Pointer selectedPointSet = dynamic_cast(m_Controls.m_ReferencePointsComboBox->GetSelectedNode()->GetData()); m_Controls.m_CurrentPointLabel->setText("Point " + QString::number(m_currentPoint) + " of " + QString::number(selectedPointSet->GetSize())); m_allErrors = std::vector(); m_allReferencePoints = std::vector(); for (int i = 0; i < selectedPointSet->GetSize(); i++) { m_allReferencePoints.push_back(selectedPointSet->GetPoint(i)); } } void QmitkUltrasoundCalibration::OnAddCurrentTipPositionForVerification() { if (m_currentPoint == -1) { MITK_WARN << "Cannot add point"; return; } if (m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource().IsNull() || (m_Controls.m_VerificationPointerChoser->GetSelectedToolID() == -1)) { MITK_WARN << "No tool selected, aborting"; return; } mitk::NavigationData::Pointer currentPointerData = m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource()->GetOutput( m_Controls.m_VerificationPointerChoser->GetSelectedToolID()); mitk::Point3D currentTipPosition = currentPointerData->GetPosition(); double currentError = m_allReferencePoints.at(m_currentPoint).EuclideanDistanceTo(currentTipPosition); MITK_INFO << "Current Error: " << currentError << " mm"; m_allErrors.push_back(currentError); if (++m_currentPoint < static_cast(m_allReferencePoints.size())) { m_Controls.m_CurrentPointLabel->setText("Point " + QString::number(m_currentPoint) + " of " + QString::number(m_allReferencePoints.size())); } else { m_currentPoint = -1; double meanError = 0; for (std::size_t i = 0; i < m_allErrors.size(); ++i) { meanError += m_allErrors[i]; } meanError /= m_allErrors.size(); QString result = "Finished verification! \n Verification of " + QString::number(m_allErrors.size()) + " points, mean error: " + QString::number(meanError) + " mm"; m_Controls.m_ResultsTextEdit->setText(result); MITK_INFO << result.toStdString(); } } void QmitkUltrasoundCalibration::OnStartCalibrationProcess() { // US Image Stream m_Node = dynamic_cast(this->GetDataStorage()->GetNamedNode("US Viewing Stream - Image 0")->CreateAnother().GetPointer()); m_Node->SetName("US Calibration Viewing Stream"); this->GetDataStorage()->Add(m_Node); // data node for calibration point set m_CalibNode = mitk::DataNode::New(); m_CalibNode->SetName("Tool Calibration Points"); m_CalibNode->SetData(this->m_CalibPointsTool); this->GetDataStorage()->Add(m_CalibNode); // data node for world point set m_WorldNode = mitk::DataNode::New(); m_WorldNode->SetName("Image Calibration Points"); m_WorldNode->SetData(this->m_CalibPointsImage); this->GetDataStorage()->Add(m_WorldNode); m_CombinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); m_CombinedModality->SetCalibration(mitk::AffineTransform3D::New()); // dummy calibration because without a calibration // the comined modality was laggy (maybe a bug?) if (m_CombinedModality.IsNull()) { return; } m_Tracker = m_CombinedModality->GetNavigationDataSource(); // Construct Pipeline this->m_NeedleProjectionFilter->SetInput(0, m_Tracker->GetOutput(0)); QApplication::setOverrideCursor(Qt::WaitCursor); // make sure that the combined modality is in connected state before using it if (m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Connected) { m_CombinedModality->GetUltrasoundDevice()->Connect(); } if (m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Activated) { m_CombinedModality->GetUltrasoundDevice()->Activate(); } QApplication::restoreOverrideCursor(); this->SwitchFreeze(); // Trigger the ProbeChanged method for initializing/updating the spacing of the ultrasound image correctly std::string probeName = m_CombinedModality->GetUltrasoundDevice()->GetCurrentProbe()->GetName(); m_CombinedModality->GetUltrasoundDevice()->ProbeChanged(probeName); mitk::DataNode::Pointer usNode = this->GetDataStorage()->GetNamedNode("US Viewing Stream - Image 0"); if (usNode.IsNotNull()) { this->GetDataStorage()->Remove(usNode); } // Todo: Maybe display this elsewhere this->ShowNeedlePath(); // Switch active tab to Calibration page m_Controls.m_ToolBox->setItemEnabled(1, true); m_Controls.m_ToolBox->setCurrentIndex(1); } void QmitkUltrasoundCalibration::OnStartPlusCalibration() { if (m_CombinedModality.IsNull()) { m_CombinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (m_CombinedModality.IsNull()) { return; } // something went wrong, there is no combined modality } // setup server to send UltrasoundImages to PLUS mitk::IGTLServer::Pointer m_USServer = mitk::IGTLServer::New(true); m_USServer->SetName("EchoTrack Image Source"); m_USServer->SetHostname("127.0.0.1"); m_USServer->SetPortNumber(18944); m_USMessageProvider = mitk::IGTLMessageProvider::New(); m_USMessageProvider->SetIGTLDevice(m_USServer); m_USMessageProvider->SetFPS(5); m_USImageToIGTLMessageFilter = mitk::ImageToIGTLMessageFilter::New(); m_USImageToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetUltrasoundDevice()); m_USImageToIGTLMessageFilter->SetName("USImage Filter"); // setup server to send TrackingData to PLUS m_TrackingServer = mitk::IGTLServer::New(true); m_TrackingServer->SetName("EchoTrack Tracking Source"); m_TrackingServer->SetHostname("127.0.0.1"); m_TrackingServer->SetPortNumber(18945); m_TrackingMessageProvider = mitk::IGTLMessageProvider::New(); m_TrackingMessageProvider->SetIGTLDevice(m_TrackingServer); m_TrackingMessageProvider->SetFPS(5); m_TrackingToIGTLMessageFilter = mitk::NavigationDataToIGTLMessageFilter::New(); m_TrackingToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetTrackingDeviceDataSource()); m_TrackingToIGTLMessageFilter->SetName("Tracker Filter"); typedef itk::SimpleMemberCommand CurCommandType; CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction(this, &QmitkUltrasoundCalibration::OnPlusConnected); this->m_NewConnectionObserverTag = this->m_TrackingServer->AddObserver(mitk::NewClientConnectionEvent(), newConnectionCommand); // Open connections of both servers if (m_USServer->OpenConnection()) { MITK_INFO << "US Server opened its connection successfully"; m_USServer->StartCommunication(); } else { MITK_INFO << "US Server could not open its connection"; } if (m_TrackingServer->OpenConnection()) { MITK_INFO << "Tracking Server opened its connection successfully"; m_TrackingServer->StartCommunication(); } else { MITK_INFO << "Tracking Server could not open its connection"; } if (m_USMessageProvider->IsCommunicating() && m_TrackingMessageProvider->IsCommunicating()) { m_Controls.m_StartPlusCalibrationButton->setEnabled(false); m_Controls.m_GetCalibrationFromPLUS->setEnabled(true); m_Controls.m_StartStreaming->setEnabled(false); m_Controls.m_SavePlusCalibration->setEnabled(false); m_Controls.m_SetupStatus->setStyleSheet("QLabel { color : green; }"); m_Controls.m_SetupStatus->setText("Setup successfull you can now connect PLUS"); } else { m_Controls.m_SetupStatus->setStyleSheet("QLabel { color : red; }"); m_Controls.m_SetupStatus->setText("Something went wrong. Please try again"); } } void QmitkUltrasoundCalibration::OnStopPlusCalibration() { // closing all server and clients when PlusCalibration is finished if (m_USMessageProvider.IsNotNull()) { if (m_USMessageProvider->IsStreaming()) { m_USMessageProvider->StopStreamingOfSource(m_USImageToIGTLMessageFilter); } } if (m_TrackingMessageProvider.IsNotNull()) { if (m_TrackingMessageProvider->IsStreaming()) { m_TrackingMessageProvider->StopStreamingOfSource(m_TrackingToIGTLMessageFilter); } } if (m_USServer.IsNotNull()) { m_USServer->CloseConnection(); } if (m_TrackingServer.IsNotNull()) { m_TrackingServer->CloseConnection(); } if (m_TransformClient.IsNotNull()) { m_TransformClient->CloseConnection(); } m_Controls.m_GotCalibrationLabel->setText(""); m_Controls.m_ConnectionStatus->setText(""); m_Controls.m_SetupStatus->setText(""); m_Controls.m_StartPlusCalibrationButton->setEnabled(true); m_StreamingTimer->stop(); delete m_StreamingTimer; } void QmitkUltrasoundCalibration::OnPlusConnected() { emit NewConnectionSignal(); } void QmitkUltrasoundCalibration::OnNewConnection() { m_Controls.m_StartStreaming->setEnabled(true); m_Controls.m_ConnectionStatus->setStyleSheet("QLabel { color : green; }"); m_Controls.m_ConnectionStatus->setText("Connection successfull you can now start streaming"); } void QmitkUltrasoundCalibration::OnStreamingTimerTimeout() { m_USMessageProvider->Update(); m_TrackingMessageProvider->Update(); } void QmitkUltrasoundCalibration::OnStartStreaming() { m_USMessageProvider->StartStreamingOfSource(m_USImageToIGTLMessageFilter, 5); m_TrackingMessageProvider->StartStreamingOfSource(m_TrackingToIGTLMessageFilter, 5); m_Controls.m_StartStreaming->setEnabled(false); m_Controls.m_ConnectionStatus->setText(""); m_StreamingTimer->start((1.0 / 5.0 * 1000.0)); } void QmitkUltrasoundCalibration::OnGetPlusCalibration() { m_TransformClient = mitk::IGTLClient::New(true); m_TransformClient->SetHostname("127.0.0.1"); m_TransformClient->SetPortNumber(18946); m_TransformDeviceSource = mitk::IGTLDeviceSource::New(); m_TransformDeviceSource->SetIGTLDevice(m_TransformClient); m_TransformDeviceSource->Connect(); if (m_TransformDeviceSource->IsConnected()) { MITK_INFO << "successfully connected"; m_TransformDeviceSource->StartCommunication(); if (m_TransformDeviceSource->IsCommunicating()) { MITK_INFO << "communication started"; mitk::IGTLMessage::Pointer receivedMessage; bool condition = false; igtl::Matrix4x4 transformPLUS; while (!(receivedMessage.IsNotNull() && receivedMessage->IsDataValid())) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); m_TransformDeviceSource->Update(); receivedMessage = m_TransformDeviceSource->GetOutput(); igtl::TransformMessage::Pointer msg = dynamic_cast(m_TransformDeviceSource->GetOutput()->GetMessage().GetPointer()); if (msg == nullptr || msg.IsNull()) { MITK_INFO << "Received message could not be casted to TransformMessage. Skipping..."; continue; } else { if (std::strcmp(msg->GetDeviceName(), "ImageToTracker") != 0) { MITK_INFO << "Was not Image to Tracker Transform. Skipping..."; continue; } else { msg->GetMatrix(transformPLUS); condition = true; break; } } } if (condition) { this->ProcessPlusCalibration(transformPLUS); } else { m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } else { MITK_INFO << " no connection"; m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } else { m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } void QmitkUltrasoundCalibration::ProcessPlusCalibration(igtl::Matrix4x4 &imageToTracker) { mitk::AffineTransform3D::Pointer imageToTrackerTransform = mitk::AffineTransform3D::New(); itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); rotationFloat[0][0] = imageToTracker[0][0]; rotationFloat[0][1] = imageToTracker[0][1]; rotationFloat[0][2] = imageToTracker[0][2]; rotationFloat[1][0] = imageToTracker[1][0]; rotationFloat[1][1] = imageToTracker[1][1]; rotationFloat[1][2] = imageToTracker[1][2]; rotationFloat[2][0] = imageToTracker[2][0]; rotationFloat[2][1] = imageToTracker[2][1]; rotationFloat[2][2] = imageToTracker[2][2]; translationFloat[0] = imageToTracker[0][3]; translationFloat[1] = imageToTracker[1][3]; translationFloat[2] = imageToTracker[2][3]; imageToTrackerTransform->SetTranslation(translationFloat); imageToTrackerTransform->SetMatrix(rotationFloat); m_CombinedModality->SetCalibration(imageToTrackerTransform); m_Controls.m_ToolBox->setItemEnabled(2, true); m_Controls.m_SavePlusCalibration->setEnabled(true); m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : green; }"); m_Controls.m_GotCalibrationLabel->setText("Recieved Calibration from PLUS you can now save it"); } void QmitkUltrasoundCalibration::OnStopCalibrationProcess() { this->ClearTemporaryMembers(); m_Timer->stop(); this->GetDataStorage()->Remove(m_Node); m_Node = nullptr; this->GetDataStorage()->Remove(m_CalibNode); m_CalibNode = nullptr; this->GetDataStorage()->Remove(m_WorldNode); m_WorldNode = nullptr; m_Controls.m_ToolBox->setCurrentIndex(0); } void QmitkUltrasoundCalibration::OnDeviceServiceEvent(const ctkServiceEvent event) { if (m_CombinedModality.IsNull() || event.getType() != ctkServiceEvent::MODIFIED) { return; } ctkServiceReference service = event.getServiceReference(); QString curDepth = service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH)).toString(); if (m_CurrentDepth != curDepth) { m_CurrentDepth = curDepth; this->OnReset(); } } void QmitkUltrasoundCalibration::OnAddCalibPoint() { auto world = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetSelectedPosition(); this->m_CalibPointsImage->InsertPoint(m_CalibPointsCount, world); this->m_CalibPointsTool->InsertPoint(m_CalibPointsCount, this->m_FreezePoint); QString text = text.number(m_CalibPointsCount + 1); text = "Point " + text; this->m_Controls.m_CalibPointList->addItem(text); m_CalibPointsCount++; SwitchFreeze(); } void QmitkUltrasoundCalibration::OnCalibration() { if (m_CombinedModality.IsNull()) { return; } // Compute transformation vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetSourceLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints()); transform->SetTargetLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsTool)->GetPoints()); if (!m_CombinedModality->GetIsTrackedUltrasoundActive()) { if (m_Controls.m_ScaleTransform->isChecked()) { transform->SetModeToSimilarity(); } // use affine transform else { transform->SetModeToRigidBody(); } // use similarity transform: scaling is not touched MITK_INFO << "TEST"; } else { transform->SetModeToRigidBody(); // use similarity transform: scaling is not touched } transform->Modified(); transform->Update(); // Convert from vtk to itk data types itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); vtkSmartPointer m = transform->GetMatrix(); rotationFloat[0][0] = m->GetElement(0, 0); rotationFloat[0][1] = m->GetElement(0, 1); rotationFloat[0][2] = m->GetElement(0, 2); rotationFloat[1][0] = m->GetElement(1, 0); rotationFloat[1][1] = m->GetElement(1, 1); rotationFloat[1][2] = m->GetElement(1, 2); rotationFloat[2][0] = m->GetElement(2, 0); rotationFloat[2][1] = m->GetElement(2, 1); rotationFloat[2][2] = m->GetElement(2, 2); translationFloat[0] = m->GetElement(0, 3); translationFloat[1] = m->GetElement(1, 3); translationFloat[2] = m->GetElement(2, 3); mitk::PointSet::Pointer ImagePointsTransformed = m_CalibPointsImage->Clone(); this->ApplyTransformToPointSet(ImagePointsTransformed, transform); mitk::DataNode::Pointer CalibPointsImageTransformed = this->GetDataStorage()->GetNamedNode("Calibration Points Image (Transformed)"); if (CalibPointsImageTransformed.IsNull()) { CalibPointsImageTransformed = mitk::DataNode::New(); CalibPointsImageTransformed->SetName("Calibration Points Image (Transformed)"); this->GetDataStorage()->Add(CalibPointsImageTransformed); } CalibPointsImageTransformed->SetData(ImagePointsTransformed); // Set new calibration transform m_Transformation = mitk::AffineTransform3D::New(); m_Transformation->SetTranslation(translationFloat); m_Transformation->SetMatrix(rotationFloat); MITK_INFO << "New Calibration transform: " << m_Transformation; mitk::SlicedGeometry3D::Pointer sliced3d = dynamic_cast(m_Node->GetData()->GetGeometry()); mitk::PlaneGeometry::Pointer plane = const_cast(sliced3d->GetPlaneGeometry(0)); plane->SetIndexToWorldTransform(m_Transformation); // Save to US-Device m_CombinedModality->SetCalibration(m_Transformation); m_Controls.m_ToolBox->setItemEnabled(2, true); // Save to NeedleProjectionFilter m_NeedleProjectionFilter->SetTargetPlane(m_Transformation); // Update Calibration FRE m_CalibrationStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); mitk::PointSet::Pointer p1 = this->m_CalibPointsTool->Clone(); // We use clones to calculate statistics to avoid concurrency Problems // Create point set with transformed image calibration points for // calculating the difference of image calibration and tool // calibration points in one geometry space mitk::PointSet::Pointer p2 = mitk::PointSet::New(); int n = 0; for (mitk::PointSet::PointsConstIterator it = m_CalibPointsImage->Begin(); it != m_CalibPointsImage->End(); ++it, ++n) { p2->InsertPoint(n, m_Transformation->TransformPoint(it->Value())); } m_CalibrationStatistics->SetPointSets(p1, p2); // QString text = text.number(m_CalibrationStatistics->GetRMS()); QString text = QString::number(ComputeFRE(m_CalibPointsImage, m_CalibPointsTool, transform)); MITK_INFO << "Calibration FRE: " << text.toStdString().c_str(); m_Controls.m_EvalLblCalibrationFRE->setText(text); m_Node->SetStringProperty("Calibration FRE", text.toStdString().c_str()); // Enable Button to save Calibration m_Controls.m_CalibBtnSaveCalibration->setEnabled(true); } void QmitkUltrasoundCalibration::OnLoadPhantomConfiguration() { // clear all data ClearTemporaryMembers(); // reset UI m_Controls.m_CalibBtnMatchAnnotationToPhantomConfiguration->setEnabled(false); m_Controls.m_RefinePhantomAnnotationsGroupBox->setEnabled(false); m_Controls.m_CalibBtnPerformPhantomCalibration->setEnabled(false); m_Controls.m_CalibBtnSavePhantomCalibration->setEnabled(false); // open phantom configuration QString fileName = QFileDialog::getOpenFileName(nullptr, "Load phantom configuration", "", "*.mps"); // dialog closed or selection canceled if (fileName.isNull()) { return; } m_PhantomConfigurationPointSet = dynamic_cast(mitk::IOUtil::Load(fileName.toStdString()).at(0).GetPointer()); // transform phantom fiducials to tracking space mitk::NavigationData::Pointer currentSensorData = this->m_Tracker->GetOutput(0)->Clone(); for (int i = 0; i < m_PhantomConfigurationPointSet->GetSize(); i++) { mitk::Point3D phantomPoint = m_PhantomConfigurationPointSet->GetPoint(i); mitk::Point3D transformedPoint = currentSensorData->TransformPoint(phantomPoint); this->m_CalibPointsTool->InsertPoint(i, transformedPoint); } // add point set interactor for image calibration points mitk::PointSetDataInteractor::Pointer imageCalibrationPointSetInteractor = mitk::PointSetDataInteractor::New(); imageCalibrationPointSetInteractor->LoadStateMachine("PointSet.xml"); imageCalibrationPointSetInteractor->SetEventConfig("PointSetConfig.xml"); imageCalibrationPointSetInteractor->SetDataNode(m_WorldNode); imageCalibrationPointSetInteractor->SetMaxPoints(m_PhantomConfigurationPointSet->GetSize()); // Call On AddCalibPointPhantomBased() when point was added itk::SimpleMemberCommand::Pointer pointAddedCommand = itk::SimpleMemberCommand::New(); pointAddedCommand->SetCallbackFunction(this, &QmitkUltrasoundCalibration::OnPhantomCalibPointsChanged); m_CalibPointsImage->AddObserver(mitk::PointSetAddEvent(), pointAddedCommand); m_CalibPointsImage->AddObserver(mitk::PointSetMoveEvent(), pointAddedCommand); // Set size of image points points m_WorldNode->ReplaceProperty("point 2D size", mitk::FloatProperty::New(10.0)); } void QmitkUltrasoundCalibration::OnPhantomCalibPointsChanged() { int currentIndex = m_CalibPointsImage->SearchSelectedPoint(); mitk::Point3D currentImagePoint = m_CalibPointsImage->GetPoint(currentIndex); UpdatePhantomAnnotationPointVisualization(currentIndex); // create sphere to show radius in which next point has to be placed this->GetDataStorage()->Remove(this->GetDataStorage()->GetNamedNode("NextPointIndicator")); if (currentIndex < m_CalibPointsTool->GetSize() - 1) { float distanceToNextPoint = m_CalibPointsTool->GetPoint(currentIndex).EuclideanDistanceTo(m_CalibPointsTool->GetPoint(currentIndex + 1)); vtkSmartPointer vtkHelperSphere = vtkSmartPointer::New(); vtkHelperSphere->SetCenter(currentImagePoint[0], currentImagePoint[1], currentImagePoint[2]); vtkHelperSphere->SetRadius(distanceToNextPoint); vtkHelperSphere->SetPhiResolution(40); vtkHelperSphere->SetThetaResolution(40); vtkHelperSphere->Update(); mitk::Surface::Pointer helperSphere = mitk::Surface::New(); helperSphere->SetVtkPolyData(vtkHelperSphere->GetOutput()); mitk::DataNode::Pointer helperSphereNode = mitk::DataNode::New(); helperSphereNode->SetName("NextPointIndicator"); helperSphereNode->SetData(helperSphere); helperSphereNode->SetColor(0.0, 1.0, 0.0); this->GetDataStorage()->Add(helperSphereNode); } if (m_CalibPointsTool->GetSize() == m_CalibPointsImage->GetSize()) { m_Controls.m_CalibBtnMatchAnnotationToPhantomConfiguration->setEnabled(true); } } void QmitkUltrasoundCalibration::UpdatePhantomAnnotationPointVisualization(int index) { mitk::Point3D currentImagePoint = m_CalibPointsImage->GetPoint(index); // create sphere to show current fiducial std::stringstream pointName; pointName << "Point"; pointName << index; this->GetDataStorage()->Remove(this->GetDataStorage()->GetNamedNode(pointName.str())); vtkSmartPointer vtkPointSphere = vtkSmartPointer::New(); vtkPointSphere->SetCenter(currentImagePoint[0], currentImagePoint[1], currentImagePoint[2]); vtkPointSphere->SetRadius(5.0); vtkPointSphere->SetPhiResolution(40); vtkPointSphere->SetThetaResolution(40); vtkPointSphere->Update(); mitk::Surface::Pointer pointSphere = mitk::Surface::New(); pointSphere->SetVtkPolyData(vtkPointSphere->GetOutput()); mitk::DataNode::Pointer sphereNode = mitk::DataNode::New(); sphereNode->SetName(pointName.str()); sphereNode->SetData(pointSphere); sphereNode->SetColor(1.0, 1.0, 0.0); this->GetDataStorage()->Add(sphereNode); } void QmitkUltrasoundCalibration::OnMatchAnnotationToPhantomConfiguration() { // Transform pointset of phantom configuration to currently annotated image points vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetModeToRigidBody(); vtkSmartPointer toolLandmarks = this->ConvertPointSetToVtkPolyData(m_CalibPointsTool)->GetPoints(); transform->SetSourceLandmarks(toolLandmarks); transform->SetTargetLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints()); transform->Update(); // update image annotation with matched phantom configuration vtkSmartPointer transformedToolLandmarks = vtkSmartPointer::New(); transform->TransformPoints(toolLandmarks, transformedToolLandmarks); for (int i = 0; i < transformedToolLandmarks->GetNumberOfPoints(); i++) { m_CalibPointsImage->InsertPoint(i, transformedToolLandmarks->GetPoint(i)); UpdatePhantomAnnotationPointVisualization(i); } m_Controls.m_RefinePhantomAnnotationsGroupBox->setEnabled(true); m_Controls.m_CalibBtnPerformPhantomCalibration->setEnabled(true); } void QmitkUltrasoundCalibration::TranslatePhantomAnnotations(double tx, double ty, double tz) { vtkSmartPointer transform = vtkSmartPointer::New(); transform->Translate(tx, ty, tz); vtkSmartPointer currentPoints = this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints(); vtkSmartPointer transformedPoints = vtkSmartPointer::New(); transform->TransformPoints(currentPoints, transformedPoints); for (int i = 0; i < transformedPoints->GetNumberOfPoints(); i++) { m_CalibPointsImage->InsertPoint(i, transformedPoints->GetPoint(i)); UpdatePhantomAnnotationPointVisualization(i); } } void QmitkUltrasoundCalibration::RotatePhantomAnnotations(double angle) { vtkSmartPointer transform = vtkSmartPointer::New(); transform->RotateZ(angle); vtkSmartPointer currentPoints = this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints(); vtkSmartPointer transformedPoints = vtkSmartPointer::New(); transform->TransformPoints(currentPoints, transformedPoints); for (int i = 0; i < transformedPoints->GetNumberOfPoints(); i++) { m_CalibPointsImage->InsertPoint(i, transformedPoints->GetPoint(i)); UpdatePhantomAnnotationPointVisualization(i); } } void QmitkUltrasoundCalibration::OnMovePhantomAnnotationsUp() { this->TranslatePhantomAnnotations(0, -m_Image->GetGeometry()->GetSpacing()[1], 0); } void QmitkUltrasoundCalibration::OnMovePhantomAnnotationsDown() { this->TranslatePhantomAnnotations(0, m_Image->GetGeometry()->GetSpacing()[1], 0); } void QmitkUltrasoundCalibration::OnMovePhantomAnnotationsLeft() { this->TranslatePhantomAnnotations(-m_Image->GetGeometry()->GetSpacing()[0], 0, 0); } void QmitkUltrasoundCalibration::OnMovePhantomAnnotationsRight() { this->TranslatePhantomAnnotations(m_Image->GetGeometry()->GetSpacing()[0], 0, 0); } void QmitkUltrasoundCalibration::OnRotatePhantomAnnotationsRight() { mitk::BoundingBox::PointType centerOfPointSet = m_CalibPointsImage->GetGeometry()->GetBoundingBox()->GetCenter(); this->TranslatePhantomAnnotations(-centerOfPointSet[0], -centerOfPointSet[1], -centerOfPointSet[2]); this->RotatePhantomAnnotations(0.5); this->TranslatePhantomAnnotations(centerOfPointSet[0], centerOfPointSet[1], centerOfPointSet[2]); } void QmitkUltrasoundCalibration::OnRotatePhantomAnnotationsLeft() { mitk::BoundingBox::PointType centerOfPointSet = m_CalibPointsImage->GetGeometry()->GetBoundingBox()->GetCenter(); this->TranslatePhantomAnnotations(-centerOfPointSet[0], -centerOfPointSet[1], -centerOfPointSet[2]); this->RotatePhantomAnnotations(-0.5); this->TranslatePhantomAnnotations(centerOfPointSet[0], centerOfPointSet[1], centerOfPointSet[2]); } void QmitkUltrasoundCalibration::OnPhantomBasedCalibration() { // perform calibration OnCalibration(); m_Controls.m_CalibBtnSavePhantomCalibration->setEnabled(true); } void QmitkUltrasoundCalibration::OnAddEvalTargetPoint() { auto world = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetSelectedPosition(); this->m_EvalPointsImage->InsertPoint(m_EvalPointsImage->GetSize(), world); this->m_EvalPointsTool->InsertPoint(m_EvalPointsTool->GetSize(), this->m_FreezePoint); QString text = text.number(this->m_EvalPointsTool->GetSize()); this->m_Controls.m_EvalLblNumTargetPoints->setText(text); // Update FREs // Update Evaluation FRE, but only if it contains more than one point (will crash otherwise) if ((m_EvalPointsProjected->GetSize() > 1) && (m_EvalPointsTool->GetSize() > 1)) { m_EvaluationStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); m_ProjectionStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); mitk::PointSet::Pointer p1 = this->m_EvalPointsTool->Clone(); // We use clones to calculate statistics to avoid concurrency Problems mitk::PointSet::Pointer p2 = this->m_EvalPointsImage->Clone(); mitk::PointSet::Pointer p3 = this->m_EvalPointsProjected->Clone(); m_EvaluationStatistics->SetPointSets(p1, p2); m_ProjectionStatistics->SetPointSets(p1, p3); QString evalText = evalText.number(m_EvaluationStatistics->GetRMS()); QString projText = projText.number(m_ProjectionStatistics->GetRMS()); m_Controls.m_EvalLblEvaluationFRE->setText(evalText); m_Controls.m_EvalLblProjectionFRE->setText(projText); } SwitchFreeze(); } void QmitkUltrasoundCalibration::OnAddEvalProjectedPoint() { MITK_WARN << "Projection Evaluation may currently be inaccurate."; // TODO: Verify correct Evaluation. Is the Point that is added really current? mitk::Point3D projection = this->m_NeedleProjectionFilter->GetProjection()->GetPoint(1); m_EvalPointsProjected->InsertPoint(m_EvalPointsProjected->GetSize(), projection); QString text = text.number(this->m_EvalPointsProjected->GetSize()); this->m_Controls.m_EvalLblNumProjectionPoints->setText(text); } void QmitkUltrasoundCalibration::OnSaveEvaluation() { // Filename without suffix QString filename = m_Controls.m_EvalFilePath->text() + "//" + m_Controls.m_EvalFilePrefix->text(); MITK_WARN << "CANNOT SAVE, ABORTING!"; /* not working any more TODO! mitk::PointSetWriter::Pointer psWriter = mitk::PointSetWriter::New(); psWriter->SetInput(0, m_CalibPointsImage); psWriter->SetInput(1, m_CalibPointsTool); psWriter->SetInput(2, m_EvalPointsImage); psWriter->SetInput(3, m_EvalPointsTool); psWriter->SetInput(4, m_EvalPointsProjected); psWriter->SetFileName(filename.toStdString() + ".xml"); psWriter->Write(); */ // TODO: New writer for transformations must be implemented. /* mitk::TransformationFileWriter::Pointer tWriter = mitk::TransformationFileWriter::New(); tWriter->SetInput(0, m_CalibPointsImage); tWriter->SetInput(1, m_CalibPointsTool); tWriter->SetInput(2, m_EvalPointsImage); tWriter->SetInput(3, m_EvalPointsTool); tWriter->SetInput(4, m_EvalPointsProjected); tWriter->SetOutputFilename(filename.toStdString() + ".txt"); tWriter->DoWrite(this->m_Transformation); */ } void QmitkUltrasoundCalibration::OnSaveCalibration() { m_Controls.m_GotCalibrationLabel->setText(""); QString filename = QFileDialog::getSaveFileName(QApplication::activeWindow(), "Save Calibration", "", "Calibration files *.cal"); QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for writing."; return; } std::string calibrationSerialization = m_CombinedModality->SerializeCalibration(); QTextStream outStream(&file); outStream << QString::fromStdString(calibrationSerialization); // save additional information if (m_Controls.m_saveAdditionalCalibrationLog->isChecked()) { mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New(); QString filenameScene = filename + "_mitkScene.mitk"; mitk::NodePredicateNot::Pointer isNotHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); mitk::DataStorage::SetOfObjects::ConstPointer nodesToBeSaved = this->GetDataStorage()->GetSubset(isNotHelperObject); mySceneIO->SaveScene(nodesToBeSaved, this->GetDataStorage(), filenameScene.toStdString().c_str()); } } void QmitkUltrasoundCalibration::OnReset() { this->ClearTemporaryMembers(); if (m_Transformation.IsNull()) { m_Transformation = mitk::AffineTransform3D::New(); } m_Transformation->SetIdentity(); if (m_Node.IsNotNull() && (m_Node->GetData() != nullptr) && (m_Node->GetData()->GetGeometry() != nullptr)) { mitk::SlicedGeometry3D::Pointer sliced3d = dynamic_cast(m_Node->GetData()->GetGeometry()); mitk::PlaneGeometry::Pointer plane = const_cast(sliced3d->GetPlaneGeometry(0)); plane->SetIndexToWorldTransform(m_Transformation); } QString text1 = text1.number(this->m_EvalPointsTool->GetSize()); this->m_Controls.m_EvalLblNumTargetPoints->setText(text1); QString text2 = text2.number(this->m_EvalPointsProjected->GetSize()); this->m_Controls.m_EvalLblNumProjectionPoints->setText(text2); } void QmitkUltrasoundCalibration::Update() { // Update Tracking Data std::vector *datas = new std::vector(); datas->push_back(m_Tracker->GetOutput()); m_Controls.m_CalibTrackingStatus->SetNavigationDatas(datas); m_Controls.m_CalibTrackingStatus->Refresh(); m_Controls.m_EvalTrackingStatus->SetNavigationDatas(datas); m_Controls.m_EvalTrackingStatus->Refresh(); m_CombinedModality->Modified(); m_CombinedModality->Update(); // Update US Image mitk::Image::Pointer image = m_CombinedModality->GetOutput(); // make sure that always the current image is set to the data node if (image.IsNotNull() && m_Node->GetData() != image.GetPointer() && image->IsInitialized()) { m_Node->SetData(image); } // Update Needle Projection m_NeedleProjectionFilter->Update(); // only update 2d window because it is faster this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); } void QmitkUltrasoundCalibration::SwitchFreeze() { m_Controls.m_CalibBtnAddPoint->setEnabled(false); // generally deactivate // We use the activity state of the timer to determine whether we are currently viewing images if (!m_Timer->isActive()) // Activate Imaging { // if (m_Node) m_Node->ReleaseData(); if (m_CombinedModality.IsNull()) { m_Timer->stop(); return; } m_CombinedModality->Update(); m_Image = m_CombinedModality->GetOutput(); if (m_Image.IsNotNull() && m_Image->IsInitialized()) { m_Node->SetData(m_Image); } std::vector datas; datas.push_back(m_Tracker->GetOutput()); m_Controls.m_CalibTrackingStatus->SetNavigationDatas(&datas); m_Controls.m_CalibTrackingStatus->ShowStatusLabels(); m_Controls.m_CalibTrackingStatus->Refresh(); m_Controls.m_EvalTrackingStatus->SetNavigationDatas(&datas); m_Controls.m_EvalTrackingStatus->ShowStatusLabels(); m_Controls.m_EvalTrackingStatus->Refresh(); int interval = 40; m_Timer->setInterval(interval); m_Timer->start(); m_CombinedModality->SetIsFreezed(false); } else if (this->m_Tracker->GetOutput(0)->IsDataValid()) { // deactivate Imaging m_Timer->stop(); // Remember last tracking coordinates m_FreezePoint = this->m_Tracker->GetOutput(0)->GetPosition(); m_Controls.m_CalibBtnAddPoint->setEnabled(true); // activate only, if valid point is set m_CombinedModality->SetIsFreezed(true); } } void QmitkUltrasoundCalibration::ShowNeedlePath() { // Init Filter this->m_NeedleProjectionFilter->SelectInput(0); // Create Node for Pointset mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Needle Path"); if (node.IsNull()) { node = mitk::DataNode::New(); node->SetName("Needle Path"); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); this->GetDataStorage()->Add(node); } } void QmitkUltrasoundCalibration::ClearTemporaryMembers() { m_CalibPointsTool->Clear(); m_CalibPointsImage->Clear(); m_CalibPointsCount = 0; m_EvalPointsImage->Clear(); m_EvalPointsTool->Clear(); m_EvalPointsProjected->Clear(); this->m_Controls.m_CalibPointList->clear(); m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; } vtkSmartPointer QmitkUltrasoundCalibration::ConvertPointSetToVtkPolyData(mitk::PointSet::Pointer PointSet) { vtkSmartPointer returnValue = vtkSmartPointer::New(); vtkSmartPointer points = vtkSmartPointer::New(); for (int i = 0; i < PointSet->GetSize(); i++) { double point[3] = {PointSet->GetPoint(i)[0], PointSet->GetPoint(i)[1], PointSet->GetPoint(i)[2]}; points->InsertNextPoint(point); } vtkSmartPointer temp = vtkSmartPointer::New(); temp->SetPoints(points); vtkSmartPointer vertexFilter = vtkSmartPointer::New(); vertexFilter->SetInputData(temp); vertexFilter->Update(); returnValue->ShallowCopy(vertexFilter->GetOutput()); return returnValue; } double QmitkUltrasoundCalibration::ComputeFRE(mitk::PointSet::Pointer imageFiducials, mitk::PointSet::Pointer realWorldFiducials, vtkSmartPointer transform) { if (imageFiducials->GetSize() != realWorldFiducials->GetSize()) return -1; double FRE = 0; for (int i = 0; i < imageFiducials->GetSize(); ++i) { itk::Point current_image_fiducial_point = imageFiducials->GetPoint(i); if (transform != nullptr) { current_image_fiducial_point = transform->TransformPoint( imageFiducials->GetPoint(i)[0], imageFiducials->GetPoint(i)[1], imageFiducials->GetPoint(i)[2]); } double cur_error_squared = current_image_fiducial_point.SquaredEuclideanDistanceTo(realWorldFiducials->GetPoint(i)); FRE += cur_error_squared; } FRE = sqrt(FRE / (double)imageFiducials->GetSize()); return FRE; } void QmitkUltrasoundCalibration::ApplyTransformToPointSet(mitk::PointSet::Pointer pointSet, vtkSmartPointer transform) { for (int i = 0; i < pointSet->GetSize(); ++i) { itk::Point current_point_transformed = itk::Point(); current_point_transformed = transform->TransformPoint(pointSet->GetPoint(i)[0], pointSet->GetPoint(i)[1], pointSet->GetPoint(i)[2]); pointSet->SetPoint(i, current_point_transformed); } } void QmitkUltrasoundCalibration::OnFreezeClicked() { if (m_CombinedModality.IsNull()) { return; } if (m_CombinedModality->GetIsFreezed()) { // device was already frozen so we need to delete all spacing points because they need to be collected all at once // no need to check if all four points are already collected, because if that's the case you can no longer click the // Freeze button m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; m_Controls.m_SpacingAddPoint->setEnabled(false); } else { m_Controls.m_SpacingAddPoint->setEnabled(true); } SwitchFreeze(); } void QmitkUltrasoundCalibration::OnAddSpacingPoint() { auto point = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetSelectedPosition(); this->m_SpacingPoints->InsertPoint(m_SpacingPointsCount, point); QString text = text.number(m_SpacingPointsCount + 1); text = "Point " + text; this->m_Controls.m_SpacingPointsList->addItem(text); m_SpacingPointsCount++; if (m_SpacingPointsCount == 4) // now we have all 4 points needed { m_Controls.m_SpacingAddPoint->setEnabled(false); m_Controls.m_CalculateSpacing->setEnabled(true); m_Controls.m_SpacingBtnFreeze->setEnabled(false); } } void QmitkUltrasoundCalibration::OnCalculateSpacing() { mitk::Point3D horizontalOne = m_SpacingPoints->GetPoint(0); mitk::Point3D horizontalTwo = m_SpacingPoints->GetPoint(1); mitk::Point3D verticalOne = m_SpacingPoints->GetPoint(2); mitk::Point3D verticalTwo = m_SpacingPoints->GetPoint(3); // Get the distances between the points in the image double xDistance = horizontalOne.EuclideanDistanceTo(horizontalTwo); double yDistance = verticalOne.EuclideanDistanceTo(verticalTwo); // Calculate the spacing of the image and fill a vector with it double xSpacing = 30 / xDistance; double ySpacing = 20 / yDistance; m_CombinedModality->GetUltrasoundDevice()->SetSpacing(xSpacing, ySpacing); // Now that the spacing is set clear all stuff and return to Calibration m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; m_CombinedModality->SetIsFreezed(false); } void QmitkUltrasoundCalibration::OnUSDepthChanged(const std::string &key, const std::string &) { // whenever depth of USImage is changed the spacing should no longer be overwritten if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { } } diff --git a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/USNavigation.cpp b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/USNavigation.cpp index 7709db6833..51f1e8fb6f 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/USNavigation.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/USNavigation.cpp @@ -1,404 +1,402 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include // Qmitk #include "USNavigation.h" #include //MITK #include #include #include #include // VTK #include // Qt #include #include #include const std::string USNavigation::VIEW_ID = "org.mitk.views.usnavigation"; void USNavigation::SetFocus() { // m_Controls.buttonPerformImageProcessing->setFocus(); } USNavigation::USNavigation() : m_ImageAlreadySetToNode(false) { } void USNavigation::CreateQtPartControl( QWidget *parent ) { m_Timer = new QTimer(this); m_RangeMeterTimer = new QTimer(this); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); m_Controls.m_ZonesWidget->SetDataStorage(this->GetDataStorage()); // Timer connect( m_Timer, SIGNAL(timeout()), this, SLOT(Update())); connect( m_RangeMeterTimer, SIGNAL(timeout()), this, SLOT(UpdateMeters())); connect( m_Controls.m_BtnSelectDevices, SIGNAL(clicked()), this, SLOT(OnSelectDevices()) ); connect( m_Controls.m_CombinedModalitySelectionWidget, SIGNAL(SignalReadyForNextStep()), this, SLOT(OnDeviceSelected()) ); connect( m_Controls.m_CombinedModalitySelectionWidget, SIGNAL(SignalNoLongerReadyForNextStep()), this, SLOT(OnDeviceDeselected()) ); connect( m_Controls.m_TabWidget, SIGNAL(currentChanged ( int )), this, SLOT(OnTabSwitch( int )) ); // Zones connect( m_Controls.m_BtnFreeze, SIGNAL(clicked()), this, SLOT(OnFreeze()) ); connect( m_Controls.m_ZonesWidget, SIGNAL(ZoneAdded()), this, SLOT(OnZoneAdded()) ); // Navigation connect( m_Controls.m_BtnStartIntervention, SIGNAL(clicked ()), this, SLOT(OnStartIntervention()) ); connect( m_Controls.m_BtnReset, SIGNAL(clicked ()), this, SLOT(OnReset()) ); connect( m_Controls.m_BtnNeedleView, SIGNAL(clicked ()), this, SLOT(OnNeedleViewToogle()) ); m_Freeze = false; m_IsNeedleViewActive = false; m_Controls.m_TabWidget->setTabEnabled(1, false); m_Controls.m_TabWidget->setTabEnabled(2, false); m_ZoneFilter = mitk::NodeDisplacementFilter::New(); m_NeedleProjectionFilter = mitk::NeedleProjectionFilter::New(); m_SmoothingFilter = mitk::NavigationDataSmoothingFilter::New(); m_CameraVis = mitk::CameraVisualization::New(); m_RangeMeterStyle = "QProgressBar:horizontal {\nborder: 1px solid gray;\nborder-radius: 3px;\nbackground: white;\npadding: 1px;\ntext-align: center;\n}\nQProgressBar::chunk:horizontal {\nbackground: qlineargradient(x1: 0, y1: 0.5, x2: 1, y2: 0.5, stop: 0 #StartColor#, stop: 0.8 #StartColor#, stop: 1 #StopColor#);\n}"; QBoxLayout * layout = new QBoxLayout(QBoxLayout::Down, m_Controls.m_RangeBox); // Pedal Support for Needle View QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_PageDown), parent); QObject::connect(shortcut, SIGNAL(activated()), m_Controls.m_BtnNeedleView, SLOT(animateClick()) ); m_Controls.m_CombinedModalitySelectionWidget->OnActivateStep(); } void USNavigation::OnDeviceSelected() { m_Controls.m_BtnSelectDevices->setEnabled(true); } void USNavigation::OnDeviceDeselected() { m_Controls.m_BtnSelectDevices->setEnabled(false); m_Controls.m_TabWidget->setCurrentIndex(0); m_Controls.m_TabWidget->setTabEnabled(1, false); m_Controls.m_TabWidget->setTabEnabled(2, false); } void USNavigation::OnSelectDevices(){ m_USDevice = m_Controls.m_CombinedModalitySelectionWidget->GetSelectedCombinedModality(); if (m_USDevice.IsNull()) { MITK_WARN << "No device selected."; return; } QApplication::setOverrideCursor(Qt::WaitCursor); // make sure that the combined modality is in connected state before using it if ( m_USDevice->GetDeviceState() < mitk::USDevice::State_Connected ) { m_USDevice->Connect(); } if ( m_USDevice->GetDeviceState() < mitk::USDevice::State_Activated ) { m_USDevice->Activate(); } QApplication::restoreOverrideCursor(); m_Tracker = m_USDevice->GetNavigationDataSource(); // Build Pipeline m_ZoneFilter->SetInput(0, m_Tracker->GetOutput(0)); m_ZoneFilter->SetInput(1, m_Tracker->GetOutput(1)); m_ZoneFilter->SelectInput(1); m_NeedleProjectionFilter->SetInput(0, m_ZoneFilter->GetOutput(0)); m_NeedleProjectionFilter->SetInput(1, m_ZoneFilter->GetOutput(1)); m_NeedleProjectionFilter->SelectInput(0); m_NeedleProjectionFilter->SetTargetPlane(m_USDevice->GetCalibration()); // Setting up the Camera Visualization Filter mitk::BaseRenderer* renderer = mitk::BaseRenderer::GetInstance(this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("3d")->GetRenderWindow()); m_CameraVis->SetInput(0, m_NeedleProjectionFilter->GetOutput(0)); m_CameraVis->SetRenderer( renderer ); m_CameraVis->SetFocalLength(40); mitk::Vector3D direction; direction[0] = 0; direction[1] = 0; direction[2] = 1; m_CameraVis->SetDirectionOfProjectionInToolCoordinates(direction); direction[0] = -1; direction[1] = 0; direction[2] = 0; m_CameraVis->SetViewUpInToolCoordinates(direction); // Create Node for Needle Projection mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Needle Path"); if ( node.IsNull() ) { node = mitk::DataNode::New(); node->SetName("Needle Path"); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); this->GetDataStorage()->Add(node); node->SetFloatProperty("opacity", 0.80f ); } m_Timer->start(15); // Create Node for US Stream m_USStream = mitk::DataNode::New(); m_USStream->SetName("US Image Stream"); m_USStream->SetFloatProperty("opacity", 0.80f ); this->GetDataStorage()->Add(m_USStream); // Switch active tab to next page m_Controls.m_TabWidget->setTabEnabled(1, true); m_Controls.m_TabWidget->setTabEnabled(2, true); m_Controls.m_TabWidget->setCurrentIndex(1); } void USNavigation::Update() { if (m_Freeze) return; // Update NeedleVisFilter only if the view is desired if (! m_IsNeedleViewActive) m_NeedleProjectionFilter->Update(); else m_CameraVis->Update(); //only Update USImage every other time m_UpdateImage ++; if (m_UpdateImage) { m_USDevice->Modified(); m_USDevice->Update(); mitk::Image::Pointer image = m_USDevice->GetOutput(); if ( ! m_ImageAlreadySetToNode && image.IsNotNull() && image->IsInitialized() ) { m_USStream->SetData(image); m_ImageAlreadySetToNode = true; // make a reinit on the ultrasound image mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if ( renderWindow != nullptr && image->GetTimeGeometry()->IsValid() ) { - renderWindow->GetRenderingManager()->InitializeViews( - image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); - renderWindow->GetRenderingManager()->RequestUpdateAll(); + renderWindow->GetRenderingManager()->InitializeViews(image->GetTimeGeometry()); } } this->RequestRenderWindowUpdate(); } } ///////////////////// Range Meter //////////////// void USNavigation::SetupProximityView() { // make sure that the data nodes in m_Zones are exactly the same as // the zone nodes of the zone node widget m_Zones.clear(); mitk::DataStorage::SetOfObjects::ConstPointer zoneNodes = m_Controls.m_ZonesWidget->GetZoneNodes(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = zoneNodes->Begin(); it != zoneNodes->End(); ++it) { m_Zones.push_back(it->Value()); } QLayout * layout = m_Controls.m_RangeBox->layout(); for (int i = 0; i < m_Zones.size(); i++) { QProgressBar * meter = CreateRangeMeter(i); layout->addWidget(meter); m_RangeMeters.push_back(meter); } m_RangeMeterTimer->start(100); } QProgressBar* USNavigation::CreateRangeMeter(int i) { mitk::DataNode::Pointer zone = m_Zones.at(i); float zoneColor[3]; bool success = m_Zones.at(i)->GetColor(zoneColor); QString zoneColorString = "#555555"; if (success) { QString zoneColorString = QString("#%1%2%3").arg(static_cast(zoneColor[0]*255), 2, 16, QChar('0')) .arg(static_cast(zoneColor[1]*255), 2, 16, QChar('0')).arg(static_cast(zoneColor[2]*255), 2, 16, QChar('0')); } QProgressBar* meter = new QProgressBar(); meter->setMinimum(0); meter->setMaximum(100); meter->setValue(0); QString zoneName = zone->GetName().c_str(); meter->setFormat(zoneName + ": No Data"); QString style = m_RangeMeterStyle; style = style.replace("#StartColor#", zoneColorString); style = style.replace("#StopColor#", zoneColorString); meter->setStyleSheet(style); meter->setVisible(true); return meter; } void USNavigation::UpdateMeters() { // Get NeedlePosition mitk::NavigationData::Pointer needle = this->m_Tracker->GetOutput(0); if (! needle->IsDataValid()) return; mitk::Point3D needlePosition = needle->GetPosition(); // Update each meter for (int i = 0; i < m_Zones.size(); i++) { mitk::Point3D zoneOrigin = m_Zones.at(i)->GetData()->GetGeometry()->GetOrigin(); // calculate absolute distance mitk::ScalarType distance = sqrt( pow(zoneOrigin[0] - needlePosition[0], 2) + pow(zoneOrigin[1] - needlePosition[1], 2) + pow(zoneOrigin[2] - needlePosition[2], 2) ); // Subtract zone size float zoneSize; m_Zones.at(i)->GetFloatProperty("zone.size", zoneSize); distance = distance - zoneSize; // Prepare new Style float zoneColor[3]; m_Zones.at(i)->GetColor(zoneColor); QString zoneColorString = QString("#%1%2%3").arg(static_cast(zoneColor[0]*255), 2, 16, QChar('0')) .arg(static_cast(zoneColor[1]*255), 2, 16, QChar('0')).arg(static_cast(zoneColor[2]*255), 2, 16, QChar('0')); QString style = m_RangeMeterStyle; QString text = m_Zones.at(i)->GetName().c_str(); int value = 0; // There Are now four possible Outcomes // 1) Needle is inside zone (bad news) if (distance < 0) { style = style.replace("#StartColor#", "red"); style = style.replace("#StopColor#", "red"); text = text + ": VIOLATED"; value = 100; } // 2) Needle is close to Zone else if (distance < WARNRANGE) { style = style.replace("#StartColor#", zoneColorString); style = style.replace("#StopColor#", "red"); text = text + ": " + QString::number(distance) + " mm"; value = 100 - 100 * ((float) distance / (float )MAXRANGE); } // 3) Needle is away from zone else if (distance < MAXRANGE) { style = style.replace("#StartColor#", zoneColorString); style = style.replace("#StopColor#", zoneColorString); text = text + ": " + QString::number(distance) + " mm"; value = 100 - 100 * ((float) distance / (float )MAXRANGE); } // 4) Needle is far away from zone else { style = style.replace("#StartColor#", zoneColorString); style = style.replace("#StopColor#", zoneColorString); text = text + ": " + QString::number(distance) + " mm"; value = 0; } QProgressBar * meter = this->m_RangeMeters.at(i); meter->setStyleSheet(style); meter->setFormat(text); meter->setValue(value); } } /////////////////// Intervention /////////////////////// void USNavigation::OnStartIntervention() { this->ResetRangeMeters(); m_Controls.m_TabWidget->setCurrentIndex(2); this->SetupProximityView(); } void USNavigation::OnFreeze() { // Swap Freeze State m_Freeze = ! m_Freeze; if ( m_Freeze ) { m_Controls.m_ZonesWidget->OnStartAddingZone(); } else { m_Controls.m_ZonesWidget->OnAbortAddingZone(); } } void USNavigation::OnReset() { // Reset Zones m_ZoneFilter->ResetNodes(); m_Zones.clear(); m_Controls.m_ZonesWidget->OnResetZones(); this->ResetRangeMeters(); m_RangeMeters.clear(); m_RangeMeterTimer->stop(); } void USNavigation::OnNeedleViewToggle() { m_IsNeedleViewActive = m_Controls.m_BtnNeedleView->isChecked(); mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Needle Path"); if ( node.IsNotNull() ) node->SetVisibility( ! m_IsNeedleViewActive ); } void USNavigation::OnZoneAdded() { if ( m_Freeze ) { m_Controls.m_BtnFreeze->setChecked(false); m_Freeze = false; } mitk::DataStorage::SetOfObjects::ConstPointer zoneNodes = m_Controls.m_ZonesWidget->GetZoneNodes(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = zoneNodes->Begin(); it != zoneNodes->End(); ++it) { // add all zones to zone filter which aren't added until now if ( find(m_Zones.begin(), m_Zones.end(), it->Value()) == m_Zones.end() ) { m_Zones.push_back(it->Value()); m_ZoneFilter->AddNode(it->Value()); } } } void USNavigation::ResetRangeMeters() { m_RangeMeters.clear(); QLayout* layout = m_Controls.m_RangeBox->layout(); QLayoutItem *item; while((item = layout->takeAt(0))) { if (item->widget()) { delete item->widget(); } delete item; } } diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp index 246b89b50a..03eecb8554 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp @@ -1,101 +1,100 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include //Mitk #include #include #include #include #include -#include #include // Qmitk #include "QmitkIGTFiducialRegistration.h" #include // Qt #include #include #include // MicroServices #include #include #include "usServiceReference.h" const std::string QmitkIGTFiducialRegistration::VIEW_ID = "org.mitk.views.IGTFiducialRegistration"; void QmitkIGTFiducialRegistration::SetFocus() { } void QmitkIGTFiducialRegistration::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); //Connect signals and slots connect(m_Controls.m_ChooseSelectedPointer, SIGNAL(clicked()), this, SLOT(PointerSelectionChanged())); connect(m_Controls.m_ChooseSelectedImage, SIGNAL(clicked()), this, SLOT(ImageSelectionChanged())); //Initialize Combobox m_Controls.m_DataStorageComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_DataStorageComboBox->SetAutoSelectNewItems(false); m_Controls.m_DataStorageComboBox->SetPredicate(mitk::NodePredicateOr::New(mitk::NodePredicateDataType::New("Surface"), mitk::NodePredicateDataType::New("Image"))); //Initialize Fiducial Registration Widget m_Controls.m_FiducialRegistrationWidget->setDataStorage(this->GetDataStorage()); m_Controls.m_FiducialRegistrationWidget->HideStaticRegistrationRadioButton(true); m_Controls.m_FiducialRegistrationWidget->HideContinousRegistrationRadioButton(true); m_Controls.m_FiducialRegistrationWidget->HideUseICPRegistrationCheckbox(true); } void QmitkIGTFiducialRegistration::InitializeRegistration() { foreach(QmitkRenderWindow* renderWindow, this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindows().values()) { this->m_Controls.m_FiducialRegistrationWidget->AddSliceNavigationController(renderWindow->GetSliceNavigationController()); } } void QmitkIGTFiducialRegistration::PointerSelectionChanged() { InitializeRegistration(); int toolID = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedToolID(); m_TrackingPointer = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(toolID); m_Controls.m_FiducialRegistrationWidget->setTrackerNavigationData(m_TrackingPointer); m_Controls.m_PointerLabel->setText(m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationTool()->GetToolName().c_str()); } void QmitkIGTFiducialRegistration::ImageSelectionChanged() { InitializeRegistration(); m_Controls.m_ImageLabel->setText(m_Controls.m_DataStorageComboBox->GetSelectedNode()->GetName().c_str()); m_Controls.m_FiducialRegistrationWidget->setImageNode(m_Controls.m_DataStorageComboBox->GetSelectedNode()); } QmitkIGTFiducialRegistration::QmitkIGTFiducialRegistration() { } QmitkIGTFiducialRegistration::~QmitkIGTFiducialRegistration() { } diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp index bab702db82..eaed8a6bcc 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp @@ -1,506 +1,503 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkImageCropperView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include const std::string QmitkImageCropperView::VIEW_ID = "org.mitk.views.qmitkimagecropper"; QmitkImageCropperView::QmitkImageCropperView(QObject *) : m_ParentWidget(nullptr) , m_BoundingShapeInteractor(nullptr) , m_CropOutsideValue(0) { CreateBoundingShapeInteractor(false); } QmitkImageCropperView::~QmitkImageCropperView() { //disable interactor if (m_BoundingShapeInteractor != nullptr) { m_BoundingShapeInteractor->SetDataNode(nullptr); m_BoundingShapeInteractor->EnableInteraction(false); } } void QmitkImageCropperView::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Controls.imageSelectionWidget->SetDataStorage(GetDataStorage()); m_Controls.imageSelectionWidget->SetNodePredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_Controls.imageSelectionWidget->SetSelectionIsOptional(true); m_Controls.imageSelectionWidget->SetAutoSelectNewNodes(true); m_Controls.imageSelectionWidget->SetEmptyInfo(QString("Please select an image node")); m_Controls.imageSelectionWidget->SetPopUpTitel(QString("Select image node")); connect(m_Controls.imageSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkImageCropperView::OnImageSelectionChanged); m_Controls.boundingBoxSelectionWidget->SetDataStorage(GetDataStorage()); m_Controls.boundingBoxSelectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")))); m_Controls.boundingBoxSelectionWidget->SetSelectionIsOptional(true); m_Controls.boundingBoxSelectionWidget->SetAutoSelectNewNodes(true); m_Controls.boundingBoxSelectionWidget->SetEmptyInfo(QString("Please select a bounding box")); m_Controls.boundingBoxSelectionWidget->SetPopUpTitel(QString("Select bounding box node")); connect(m_Controls.boundingBoxSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkImageCropperView::OnBoundingBoxSelectionChanged); connect(m_Controls.buttonCreateNewBoundingBox, SIGNAL(clicked()), this, SLOT(OnCreateNewBoundingBox())); connect(m_Controls.buttonCropping, SIGNAL(clicked()), this, SLOT(OnCropping())); connect(m_Controls.buttonMasking, SIGNAL(clicked()), this, SLOT(OnMasking())); auto lambda = [this]() { m_Controls.groupImageSettings->setVisible(!m_Controls.groupImageSettings->isVisible()); }; connect(m_Controls.buttonAdvancedSettings, &ctkExpandButton::clicked, this, lambda); connect(m_Controls.spinBoxOutsidePixelValue, SIGNAL(valueChanged(int)), this, SLOT(OnSliderValueChanged(int))); SetDefaultGUI(); m_ParentWidget = parent; this->OnImageSelectionChanged(m_Controls.imageSelectionWidget->GetSelectedNodes()); this->OnBoundingBoxSelectionChanged(m_Controls.boundingBoxSelectionWidget->GetSelectedNodes()); } void QmitkImageCropperView::OnImageSelectionChanged(QList) { bool rotationEnabled = false; auto imageNode = m_Controls.imageSelectionWidget->GetSelectedNode(); if (imageNode.IsNull()) { SetDefaultGUI(); return; } auto image = dynamic_cast(imageNode->GetData()); if (nullptr != image) { if (image->GetDimension() < 3) { QMessageBox::warning(nullptr, tr("Invalid image selected"), tr("ImageCropper only works with 3 or more dimensions."), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); SetDefaultGUI(); return; } m_ParentWidget->setEnabled(true); m_Controls.buttonCreateNewBoundingBox->setEnabled(true); vtkSmartPointer imageMat = image->GetGeometry()->GetVtkMatrix(); // check whether the image geometry is rotated; if so, no pixel aligned cropping or masking can be performed if ((imageMat->GetElement(1, 0) == 0.0) && (imageMat->GetElement(0, 1) == 0.0) && (imageMat->GetElement(1, 2) == 0.0) && (imageMat->GetElement(2, 1) == 0.0) && (imageMat->GetElement(2, 0) == 0.0) && (imageMat->GetElement(0, 2) == 0.0)) { rotationEnabled = false; m_Controls.labelWarningRotation->setVisible(false); } else { rotationEnabled = true; m_Controls.labelWarningRotation->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelWarningRotation->setVisible(true); } this->CreateBoundingShapeInteractor(rotationEnabled); if (itk::ImageIOBase::SCALAR == image->GetPixelType().GetPixelType()) { // Might be changed with the upcoming new image statistics plugin //(recomputation might be very expensive for large images ;) ) auto statistics = image->GetStatistics(); auto minPixelValue = statistics->GetScalarValueMin(); auto maxPixelValue = statistics->GetScalarValueMax(); if (minPixelValue < std::numeric_limits::min()) { minPixelValue = std::numeric_limits::min(); } if (maxPixelValue > std::numeric_limits::max()) { maxPixelValue = std::numeric_limits::max(); } m_Controls.spinBoxOutsidePixelValue->setEnabled(true); m_Controls.spinBoxOutsidePixelValue->setMaximum(static_cast(maxPixelValue)); m_Controls.spinBoxOutsidePixelValue->setMinimum(static_cast(minPixelValue)); m_Controls.spinBoxOutsidePixelValue->setValue(static_cast(minPixelValue)); } else { m_Controls.spinBoxOutsidePixelValue->setEnabled(false); } unsigned int dim = image->GetDimension(); if (dim < 2 || dim > 4) { m_ParentWidget->setEnabled(false); } if (m_Controls.boundingBoxSelectionWidget->GetSelectedNode().IsNotNull()) { m_Controls.buttonCropping->setEnabled(true); m_Controls.buttonMasking->setEnabled(true); m_Controls.buttonAdvancedSettings->setEnabled(true); m_Controls.groupImageSettings->setEnabled(true); } } } void QmitkImageCropperView::OnBoundingBoxSelectionChanged(QList) { auto boundingBoxNode = m_Controls.boundingBoxSelectionWidget->GetSelectedNode(); if (boundingBoxNode.IsNull()) { SetDefaultGUI(); m_BoundingShapeInteractor->EnableInteraction(false); m_BoundingShapeInteractor->SetDataNode(nullptr); if (m_Controls.imageSelectionWidget->GetSelectedNode().IsNotNull()) { m_Controls.buttonCreateNewBoundingBox->setEnabled(true); } return; } auto boundingBox = dynamic_cast(boundingBoxNode->GetData()); if (nullptr != boundingBox) { // node newly selected boundingBoxNode->SetVisibility(true); m_BoundingShapeInteractor->EnableInteraction(true); m_BoundingShapeInteractor->SetDataNode(boundingBoxNode); mitk::RenderingManager::GetInstance()->InitializeViews(); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (m_Controls.imageSelectionWidget->GetSelectedNode().IsNotNull()) { m_Controls.buttonCropping->setEnabled(true); m_Controls.buttonMasking->setEnabled(true); m_Controls.buttonAdvancedSettings->setEnabled(true); m_Controls.groupImageSettings->setEnabled(true); } } } void QmitkImageCropperView::OnCreateNewBoundingBox() { auto imageNode = m_Controls.imageSelectionWidget->GetSelectedNode(); if (imageNode.IsNull()) { return; } if (nullptr == imageNode->GetData()) { return; } QString name = QString::fromStdString(imageNode->GetName() + " Bounding Shape"); auto boundingShape = this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&name](const mitk::DataNode *node) { return 0 == node->GetName().compare(name.toStdString()); })); if (nullptr != boundingShape) { name = this->AdaptBoundingObjectName(name); } // get current timestep to support 3d+t images auto renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); const auto timePoint = renderWindowPart->GetSelectedTimePoint(); const auto imageGeometry = imageNode->GetData()->GetTimeGeometry()->GetGeometryForTimePoint(timePoint); auto boundingBox = mitk::GeometryData::New(); boundingBox->SetGeometry(static_cast(this->InitializeWithImageGeometry(imageGeometry))); auto boundingBoxNode = mitk::DataNode::New(); boundingBoxNode->SetData(boundingBox); boundingBoxNode->SetProperty("name", mitk::StringProperty::New(name.toStdString())); boundingBoxNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); boundingBoxNode->SetProperty("opacity", mitk::FloatProperty::New(0.6)); boundingBoxNode->SetProperty("layer", mitk::IntProperty::New(99)); boundingBoxNode->AddProperty("handle size factor", mitk::DoubleProperty::New(1.0 / 40.0)); boundingBoxNode->SetBoolProperty("pickable", true); if (!this->GetDataStorage()->Exists(boundingBoxNode)) { GetDataStorage()->Add(boundingBoxNode, imageNode); } m_Controls.boundingBoxSelectionWidget->SetCurrentSelectedNode(boundingBoxNode); } void QmitkImageCropperView::OnCropping() { this->ProcessImage(false); } void QmitkImageCropperView::OnMasking() { this->ProcessImage(true); } void QmitkImageCropperView::OnSliderValueChanged(int slidervalue) { m_CropOutsideValue = slidervalue; } void QmitkImageCropperView::CreateBoundingShapeInteractor(bool rotationEnabled) { if (m_BoundingShapeInteractor.IsNull()) { m_BoundingShapeInteractor = mitk::BoundingShapeInteractor::New(); m_BoundingShapeInteractor->LoadStateMachine("BoundingShapeInteraction.xml", us::ModuleRegistry::GetModule("MitkBoundingShape")); m_BoundingShapeInteractor->SetEventConfig("BoundingShapeMouseConfig.xml", us::ModuleRegistry::GetModule("MitkBoundingShape")); } m_BoundingShapeInteractor->SetRotationEnabled(rotationEnabled); } mitk::Geometry3D::Pointer QmitkImageCropperView::InitializeWithImageGeometry(const mitk::BaseGeometry* geometry) const { // convert a BaseGeometry into a Geometry3D (otherwise IO is not working properly) if (geometry == nullptr) mitkThrow() << "Geometry is not valid."; auto boundingGeometry = mitk::Geometry3D::New(); boundingGeometry->SetBounds(geometry->GetBounds()); boundingGeometry->SetImageGeometry(geometry->GetImageGeometry()); boundingGeometry->SetOrigin(geometry->GetOrigin()); boundingGeometry->SetSpacing(geometry->GetSpacing()); boundingGeometry->SetIndexToWorldTransform(geometry->GetIndexToWorldTransform()->Clone()); boundingGeometry->Modified(); return boundingGeometry; } void QmitkImageCropperView::ProcessImage(bool mask) { auto renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); const auto timePoint = renderWindowPart->GetSelectedTimePoint(); auto imageNode = m_Controls.imageSelectionWidget->GetSelectedNode(); if (imageNode.IsNull()) { QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing."); return; } auto boundingBoxNode = m_Controls.boundingBoxSelectionWidget->GetSelectedNode(); if (boundingBoxNode.IsNull()) { QMessageBox::information(nullptr, "Warning", "Please load and select a cropping object before starting image processing."); return; } if (!imageNode->GetData()->GetTimeGeometry()->IsValidTimePoint(timePoint)) { QMessageBox::information(nullptr, "Warning", "Please select a time point that is within the time bounds of the selected image."); return; } const auto timeStep = imageNode->GetData()->GetTimeGeometry()->TimePointToTimeStep(timePoint); auto image = dynamic_cast(imageNode->GetData()); auto boundingBox = dynamic_cast(boundingBoxNode->GetData()); if (nullptr != image && nullptr != boundingBox) { QString imageName; if (mask) { imageName = QString::fromStdString(imageNode->GetName() + "_" + boundingBoxNode->GetName() + "_masked"); } else { imageName = QString::fromStdString(imageNode->GetName() + "_" + boundingBoxNode->GetName() + "_cropped"); } if (m_Controls.checkBoxCropTimeStepOnly->isChecked()) { imageName = imageName + "_T" + QString::number(timeStep); } // image and bounding shape ok, set as input auto croppedImageNode = mitk::DataNode::New(); auto cutter = mitk::BoundingShapeCropper::New(); cutter->SetGeometry(boundingBox); // adjustable in advanced settings cutter->SetUseWholeInputRegion(mask); //either mask (mask=true) or crop (mask=false) cutter->SetOutsideValue(m_CropOutsideValue); cutter->SetUseCropTimeStepOnly(m_Controls.checkBoxCropTimeStepOnly->isChecked()); cutter->SetCurrentTimeStep(timeStep); // TODO: Add support for MultiLayer (right now only Mulitlabel support) auto labelsetImageInput = dynamic_cast(image); if (nullptr != labelsetImageInput) { cutter->SetInput(labelsetImageInput); // do the actual cutting try { cutter->Update(); } catch (const itk::ExceptionObject& e) { std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription(); QMessageBox::warning(nullptr, tr("Cropping not possible!"), tr(message.c_str()), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); return; } auto labelSetImage = mitk::LabelSetImage::New(); labelSetImage->InitializeByLabeledImage(cutter->GetOutput()); for (unsigned int i = 0; i < labelsetImageInput->GetNumberOfLayers(); i++) { labelSetImage->AddLabelSetToLayer(i, labelsetImageInput->GetLabelSet(i)); } croppedImageNode->SetData(labelSetImage); croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString())); //add cropping result to the current data storage as child node to the image node if (!m_Controls.checkOverwriteImage->isChecked()) { if (!this->GetDataStorage()->Exists(croppedImageNode)) { this->GetDataStorage()->Add(croppedImageNode, imageNode); } } else // original image will be overwritten by the result image and the bounding box of the result is adjusted { imageNode->SetData(labelSetImage); imageNode->Modified(); // Adjust coordinate system by doing a reinit on auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); tempDataStorage->InsertElement(0, imageNode); // initialize the views to the bounding geometry auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); mitk::RenderingManager::GetInstance()->InitializeViews(bounds); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } else { cutter->SetInput(image); // do the actual cutting try { cutter->Update(); } catch (const itk::ExceptionObject& e) { std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription(); QMessageBox::warning(nullptr, tr("Cropping not possible!"), tr(message.c_str()), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); return; } //add cropping result to the current data storage as child node to the image node if (!m_Controls.checkOverwriteImage->isChecked()) { croppedImageNode->SetData(cutter->GetOutput()); croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString())); croppedImageNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); mitk::LevelWindow levelWindow; imageNode->GetLevelWindow(levelWindow); croppedImageNode->SetLevelWindow(levelWindow); if (!this->GetDataStorage()->Exists(croppedImageNode)) { this->GetDataStorage()->Add(croppedImageNode, imageNode); imageNode->SetVisibility(mask); // Give the user a visual clue that something happened when image was cropped } } else // original image will be overwritten by the result image and the bounding box of the result is adjusted { mitk::LevelWindow levelWindow; imageNode->GetLevelWindow(levelWindow); imageNode->SetData(cutter->GetOutput()); imageNode->SetLevelWindow(levelWindow); // Adjust coordinate system by doing a reinit on auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); tempDataStorage->InsertElement(0, imageNode); // initialize the views to the bounding geometry auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); mitk::RenderingManager::GetInstance()->InitializeViews(bounds); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } else { QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing."); } } void QmitkImageCropperView::SetDefaultGUI() { m_Controls.labelWarningRotation->setVisible(false); m_Controls.buttonCreateNewBoundingBox->setEnabled(false); m_Controls.buttonCropping->setEnabled(false); m_Controls.buttonMasking->setEnabled(false); m_Controls.buttonAdvancedSettings->setEnabled(false); m_Controls.groupImageSettings->setEnabled(false); m_Controls.groupImageSettings->setVisible(false); m_Controls.checkOverwriteImage->setChecked(false); m_Controls.checkBoxCropTimeStepOnly->setChecked(false); } QString QmitkImageCropperView::AdaptBoundingObjectName(const QString& name) const { unsigned int counter = 2; QString newName = QString("%1 %2").arg(name).arg(counter); while (nullptr != this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&newName](const mitk::DataNode *node) { return 0 == node->GetName().compare(newName.toStdString()); }))) { newName = QString("%1 %2").arg(name).arg(++counter); } return newName; } diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp index ba833d3f10..c196df5e90 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp @@ -1,317 +1,317 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include // Mitk #include #include #include #include "mitkRegVisPropertyTags.h" #include "mitkMatchPointPropertyTags.h" #include "mitkRegEvaluationObject.h" #include "mitkRegistrationHelper.h" #include "mitkRegEvaluationMapper2D.h" #include #include "mitkProperties.h" // Qmitk #include "QmitkRenderWindow.h" #include "QmitkMatchPointRegistrationEvaluator.h" // Qt #include #include #include const std::string QmitkMatchPointRegistrationEvaluator::VIEW_ID = "org.mitk.views.matchpoint.registration.evaluator"; const std::string QmitkMatchPointRegistrationEvaluator::HelperNodeName = "RegistrationEvaluationHelper"; QmitkMatchPointRegistrationEvaluator::QmitkMatchPointRegistrationEvaluator() : m_Parent(nullptr), m_activeEvaluation(false), m_currentSelectedTimePoint(0.) { m_currentSelectedPosition.Fill(0.0); } QmitkMatchPointRegistrationEvaluator::~QmitkMatchPointRegistrationEvaluator() { if (this->m_selectedEvalNode.IsNotNull() && this->GetDataStorage().IsNotNull()) { this->GetDataStorage()->Remove(this->m_selectedEvalNode); } } void QmitkMatchPointRegistrationEvaluator::SetFocus() { } void QmitkMatchPointRegistrationEvaluator::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); } void QmitkMatchPointRegistrationEvaluator::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; this->m_Controls.registrationNodeSelector->SetDataStorage(this->GetDataStorage()); this->m_Controls.registrationNodeSelector->SetSelectionIsOptional(true); this->m_Controls.movingNodeSelector->SetDataStorage(this->GetDataStorage()); this->m_Controls.movingNodeSelector->SetSelectionIsOptional(false); this->m_Controls.targetNodeSelector->SetDataStorage(this->GetDataStorage()); this->m_Controls.targetNodeSelector->SetSelectionIsOptional(false); this->m_Controls.registrationNodeSelector->SetInvalidInfo("Select valid registration."); this->m_Controls.registrationNodeSelector->SetEmptyInfo("Assuming identity. Select registration to change."); this->m_Controls.registrationNodeSelector->SetPopUpTitel("Select registration."); this->m_Controls.registrationNodeSelector->SetPopUpHint("Select a registration object that should be evaluated. If no registration is selected, identity will be assumed for evaluation."); this->m_Controls.movingNodeSelector->SetInvalidInfo("Select moving image."); this->m_Controls.movingNodeSelector->SetPopUpTitel("Select moving image."); this->m_Controls.movingNodeSelector->SetPopUpHint("Select the moving image for the evaluation. This is the image that will be mapped by the registration."); this->m_Controls.targetNodeSelector->SetInvalidInfo("Select target image."); this->m_Controls.targetNodeSelector->SetPopUpTitel("Select target image."); this->m_Controls.targetNodeSelector->SetPopUpHint("Select the target image for the evaluation."); this->m_Controls.checkAutoSelect->setChecked(true); this->ConfigureNodePredicates(); connect(m_Controls.pbEval, SIGNAL(clicked()), this, SLOT(OnEvalBtnPushed())); connect(m_Controls.pbStop, SIGNAL(clicked()), this, SLOT(OnStopBtnPushed())); connect(m_Controls.evalSettings, SIGNAL(SettingsChanged(mitk::DataNode*)), this, SLOT(OnSettingsChanged(mitk::DataNode*))); connect(m_Controls.registrationNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkMatchPointRegistrationEvaluator::OnNodeSelectionChanged); connect(m_Controls.movingNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkMatchPointRegistrationEvaluator::OnNodeSelectionChanged); connect(m_Controls.targetNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkMatchPointRegistrationEvaluator::OnNodeSelectionChanged); this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); m_selectedEvalNode = this->GetDataStorage()->GetNamedNode(HelperNodeName); this->CheckInputs(); this->ConfigureControls(); } void QmitkMatchPointRegistrationEvaluator::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); } void QmitkMatchPointRegistrationEvaluator::RenderWindowPartDeactivated( mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); } void QmitkMatchPointRegistrationEvaluator::ConfigureNodePredicates() { this->m_Controls.registrationNodeSelector->SetNodePredicate(mitk::MITKRegistrationHelper::RegNodePredicate()); this->m_Controls.movingNodeSelector->SetNodePredicate(mitk::MITKRegistrationHelper::ImageNodePredicate()); this->m_Controls.targetNodeSelector->SetNodePredicate(mitk::MITKRegistrationHelper::ImageNodePredicate()); } void QmitkMatchPointRegistrationEvaluator::CheckInputs() { if (!m_activeEvaluation) { bool autoSelectInput = m_Controls.checkAutoSelect->isChecked() && this->m_spSelectedRegNode != this->m_Controls.registrationNodeSelector->GetSelectedNode(); this->m_spSelectedRegNode = this->m_Controls.registrationNodeSelector->GetSelectedNode(); this->m_spSelectedMovingNode = this->m_Controls.movingNodeSelector->GetSelectedNode(); this->m_spSelectedTargetNode = this->m_Controls.targetNodeSelector->GetSelectedNode(); if (this->m_spSelectedRegNode.IsNotNull() && (this->m_spSelectedMovingNode.IsNull() || autoSelectInput)) { mitk::BaseProperty* uidProp = m_spSelectedRegNode->GetData()->GetProperty(mitk::Prop_RegAlgMovingData); if (uidProp) { //search for the moving node mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New(mitk::Prop_UID, uidProp); mitk::DataNode::Pointer movingNode = this->GetDataStorage()->GetNode(predicate); if (movingNode.IsNotNull()) { this->m_spSelectedMovingNode = movingNode; QmitkSingleNodeSelectionWidget::NodeList selection({ movingNode }); this->m_Controls.movingNodeSelector->SetCurrentSelection(selection); } } } if (this->m_spSelectedRegNode.IsNotNull() && (this->m_spSelectedTargetNode.IsNull() || autoSelectInput)) { mitk::BaseProperty* uidProp = m_spSelectedRegNode->GetData()->GetProperty(mitk::Prop_RegAlgTargetData); if (uidProp) { //search for the target node mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New(mitk::Prop_UID, uidProp); mitk::DataNode::Pointer targetNode = this->GetDataStorage()->GetNode(predicate); if (targetNode.IsNotNull()) { this->m_spSelectedTargetNode = targetNode; QmitkSingleNodeSelectionWidget::NodeList selection({ targetNode }); this->m_Controls.targetNodeSelector->SetCurrentSelection(selection); } } } } } void QmitkMatchPointRegistrationEvaluator::OnNodeSelectionChanged(QList /*nodes*/) { this->CheckInputs(); this->ConfigureControls(); } void QmitkMatchPointRegistrationEvaluator::NodeRemoved(const mitk::DataNode* node) { if (node == this->m_spSelectedMovingNode || node == this->m_spSelectedRegNode || node == this->m_spSelectedTargetNode || node == this->m_selectedEvalNode) { if (node == this->m_selectedEvalNode) { this->m_selectedEvalNode = nullptr; } this->OnStopBtnPushed(); MITK_INFO << "Stopped current MatchPoint evaluation session, because at least one relevant node was removed from storage."; } } void QmitkMatchPointRegistrationEvaluator::ConfigureControls() { //config settings widget this->m_Controls.evalSettings->setVisible(m_activeEvaluation); this->m_Controls.pbEval->setEnabled(this->m_spSelectedMovingNode.IsNotNull() && this->m_spSelectedTargetNode.IsNotNull()); this->m_Controls.pbEval->setVisible(!m_activeEvaluation); this->m_Controls.pbStop->setVisible(m_activeEvaluation); this->m_Controls.registrationNodeSelector->setEnabled(!m_activeEvaluation); this->m_Controls.movingNodeSelector->setEnabled(!m_activeEvaluation); this->m_Controls.targetNodeSelector->setEnabled(!m_activeEvaluation); } void QmitkMatchPointRegistrationEvaluator::OnSliceChanged() { auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); auto currentSelectedPosition = renderWindowPart->GetSelectedPosition(nullptr); auto currentTimePoint = renderWindowPart->GetSelectedTimePoint(); if (m_currentSelectedPosition != currentSelectedPosition || m_currentSelectedTimePoint != currentTimePoint || m_selectedNodeTime > m_currentPositionTime) { //the current position has been changed or the selected node has been changed since the last position validation -> check position m_currentSelectedPosition = currentSelectedPosition; m_currentSelectedTimePoint = currentTimePoint; m_currentPositionTime.Modified(); if (this->m_selectedEvalNode.IsNotNull()) { this->m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalCurrentPosition, mitk::Point3dProperty::New(currentSelectedPosition)); } } } void QmitkMatchPointRegistrationEvaluator::OnSettingsChanged(mitk::DataNode*) { auto* renderWindowPart = this->GetRenderWindowPart(); if (nullptr != renderWindowPart) renderWindowPart->RequestUpdate(); } void QmitkMatchPointRegistrationEvaluator::OnEvalBtnPushed() { //reinit view - mitk::RenderingManager::GetInstance()->InitializeViews(m_spSelectedTargetNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->InitializeViews(m_spSelectedTargetNode->GetData()->GetTimeGeometry()); mitk::RegEvaluationObject::Pointer regEval = mitk::RegEvaluationObject::New(); mitk::MAPRegistrationWrapper::Pointer reg; if (m_spSelectedRegNode.IsNotNull()) { reg = dynamic_cast(this->m_spSelectedRegNode->GetData()); } else { //generate a dymme reg to use reg = mitk::GenerateIdentityRegistration3D(); } regEval->SetRegistration(reg); regEval->SetTargetNode(this->m_spSelectedTargetNode); regEval->SetMovingNode(this->m_spSelectedMovingNode); if (this->m_selectedEvalNode.IsNotNull()) { this->GetDataStorage()->Remove(this->m_selectedEvalNode); } this->m_selectedEvalNode = mitk::DataNode::New(); this->m_selectedEvalNode->SetData(regEval); mitk::RegEvaluationMapper2D::SetDefaultProperties(this->m_selectedEvalNode); this->m_selectedEvalNode->SetName(HelperNodeName); this->m_selectedEvalNode->SetBoolProperty("helper object", true); this->GetDataStorage()->Add(this->m_selectedEvalNode); this->m_Controls.evalSettings->SetNode(this->m_selectedEvalNode); this->OnSliceChanged(); auto* renderWindowPart = this->GetRenderWindowPart(); if (nullptr != renderWindowPart) renderWindowPart->RequestUpdate(); this->m_activeEvaluation = true; this->CheckInputs(); this->ConfigureControls(); } void QmitkMatchPointRegistrationEvaluator::OnStopBtnPushed() { this->m_activeEvaluation = false; if (this->m_selectedEvalNode.IsNotNull()) { this->GetDataStorage()->Remove(this->m_selectedEvalNode); } this->m_selectedEvalNode = nullptr; this->m_Controls.evalSettings->SetNode(this->m_selectedEvalNode); this->CheckInputs(); this->ConfigureControls(); if (nullptr != this->GetRenderWindowPart()) { this->GetRenderWindowPart()->RequestUpdate(); } } diff --git a/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.cpp b/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.cpp index 2a0fafc773..02e2705e6e 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.cpp @@ -1,519 +1,519 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include // Mitk #include #include #include #include "mitkRegVisPropertyTags.h" #include "mitkMatchPointPropertyTags.h" #include "mitkRegEvaluationObject.h" #include "mitkRegistrationHelper.h" #include "mitkRegEvaluationMapper2D.h" #include #include #include #include "mitkProperties.h" // Qmitk #include "QmitkRenderWindow.h" #include "QmitkMatchPointRegistrationManipulator.h" #include // Qt #include #include #include #include //MatchPoint #include #include #include #include #include #include #include const std::string QmitkMatchPointRegistrationManipulator::VIEW_ID = "org.mitk.views.matchpoint.registration.manipulator"; const std::string QmitkMatchPointRegistrationManipulator::HelperNodeName = "RegistrationManipulationEvaluationHelper"; QmitkMatchPointRegistrationManipulator::QmitkMatchPointRegistrationManipulator() : m_Parent(nullptr), m_activeManipulation(false), m_currentSelectedTimePoint(0.), m_internalUpdate(false) { m_currentSelectedPosition.Fill(0.0); } QmitkMatchPointRegistrationManipulator::~QmitkMatchPointRegistrationManipulator() { if (this->m_EvalNode.IsNotNull() && this->GetDataStorage().IsNotNull()) { this->GetDataStorage()->Remove(this->m_EvalNode); } } void QmitkMatchPointRegistrationManipulator::SetFocus() { } void QmitkMatchPointRegistrationManipulator::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); } void QmitkMatchPointRegistrationManipulator::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; this->m_Controls.registrationNodeSelector->SetDataStorage(this->GetDataStorage()); this->m_Controls.registrationNodeSelector->SetSelectionIsOptional(false); this->m_Controls.movingNodeSelector->SetDataStorage(this->GetDataStorage()); this->m_Controls.movingNodeSelector->SetSelectionIsOptional(false); this->m_Controls.targetNodeSelector->SetDataStorage(this->GetDataStorage()); this->m_Controls.targetNodeSelector->SetSelectionIsOptional(false); this->m_Controls.registrationNodeSelector->SetInvalidInfo("Select base registration."); this->m_Controls.registrationNodeSelector->SetPopUpTitel("Select registration."); this->m_Controls.registrationNodeSelector->SetPopUpHint("Select a registration object that should be used as starting point for the manual manipulation."); this->m_Controls.movingNodeSelector->SetInvalidInfo("Select moving image."); this->m_Controls.movingNodeSelector->SetPopUpTitel("Select moving image."); this->m_Controls.movingNodeSelector->SetPopUpHint("Select the moving image for the evaluation. This is the image that will be mapped by the registration."); this->m_Controls.targetNodeSelector->SetInvalidInfo("Select target image."); this->m_Controls.targetNodeSelector->SetPopUpTitel("Select target image."); this->m_Controls.targetNodeSelector->SetPopUpHint("Select the target image for the evaluation."); this->m_Controls.checkAutoSelect->setChecked(true); this->ConfigureNodePredicates(); connect(m_Controls.pbStart, SIGNAL(clicked()), this, SLOT(OnStartBtnPushed())); connect(m_Controls.pbCancel, SIGNAL(clicked()), this, SLOT(OnCancelBtnPushed())); connect(m_Controls.pbStore, SIGNAL(clicked()), this, SLOT(OnStoreBtnPushed())); connect(m_Controls.evalSettings, SIGNAL(SettingsChanged(mitk::DataNode*)), this, SLOT(OnSettingsChanged(mitk::DataNode*))); connect(m_Controls.radioSelectedReg, SIGNAL(toggled(bool)), this, SLOT(OnRegSourceChanged())); connect(m_Controls.comboCenter, SIGNAL(currentIndexChanged(int)), this, SLOT(OnCenterTypeChanged(int))); connect(m_Controls.manipulationWidget, SIGNAL(RegistrationChanged(map::core::RegistrationBase*)), this, SLOT(OnRegistrationChanged())); connect(m_Controls.registrationNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkMatchPointRegistrationManipulator::OnNodeSelectionChanged); connect(m_Controls.movingNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkMatchPointRegistrationManipulator::OnNodeSelectionChanged); connect(m_Controls.targetNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkMatchPointRegistrationManipulator::OnNodeSelectionChanged); this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); m_Controls.radioNewReg->setChecked(true); m_EvalNode = this->GetDataStorage()->GetNamedNode(HelperNodeName); this->CheckInputs(); this->StopSession(); this->ConfigureControls(); } void QmitkMatchPointRegistrationManipulator::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); } void QmitkMatchPointRegistrationManipulator::RenderWindowPartDeactivated( mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); } void QmitkMatchPointRegistrationManipulator::ConfigureNodePredicates() { this->m_Controls.registrationNodeSelector->SetNodePredicate(mitk::MITKRegistrationHelper::RegNodePredicate()); this->m_Controls.movingNodeSelector->SetNodePredicate(mitk::MITKRegistrationHelper::ImageNodePredicate()); this->m_Controls.targetNodeSelector->SetNodePredicate(mitk::MITKRegistrationHelper::ImageNodePredicate()); } void QmitkMatchPointRegistrationManipulator::CheckInputs() { if (!m_activeManipulation) { bool autoSelectInput = m_Controls.checkAutoSelect->isChecked() && this->m_SelectedPreRegNode != this->m_Controls.registrationNodeSelector->GetSelectedNode(); this->m_SelectedPreRegNode = this->m_Controls.registrationNodeSelector->GetSelectedNode(); this->m_SelectedMovingNode = this->m_Controls.movingNodeSelector->GetSelectedNode(); this->m_SelectedTargetNode = this->m_Controls.targetNodeSelector->GetSelectedNode(); if (this->m_SelectedPreRegNode.IsNotNull()) { mitk::MAPRegistrationWrapper* regWrapper = dynamic_cast(m_SelectedPreRegNode->GetData()); if (regWrapper) { this->m_SelectedPreReg = dynamic_cast(regWrapper->GetRegistration()); } } if (this->m_SelectedPreRegNode.IsNotNull() && (this->m_SelectedMovingNode.IsNull() || autoSelectInput)) { mitk::BaseProperty* uidProp = m_SelectedPreRegNode->GetData()->GetProperty(mitk::Prop_RegAlgMovingData); if (uidProp) { //search for the moving node mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New(mitk::Prop_UID, uidProp); mitk::DataNode::Pointer movingNode = this->GetDataStorage()->GetNode(predicate); if (movingNode.IsNotNull()) { this->m_SelectedMovingNode = movingNode; QmitkSingleNodeSelectionWidget::NodeList selection({ movingNode }); this->m_Controls.movingNodeSelector->SetCurrentSelection(selection); } } } if (this->m_SelectedPreRegNode.IsNotNull() && (this->m_SelectedTargetNode.IsNull() || autoSelectInput)) { mitk::BaseProperty* uidProp = m_SelectedPreRegNode->GetData()->GetProperty(mitk::Prop_RegAlgTargetData); if (uidProp) { //search for the target node mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New(mitk::Prop_UID, uidProp); mitk::DataNode::Pointer targetNode = this->GetDataStorage()->GetNode(predicate); if (targetNode.IsNotNull()) { this->m_SelectedTargetNode = targetNode; QmitkSingleNodeSelectionWidget::NodeList selection({ targetNode }); this->m_Controls.targetNodeSelector->SetCurrentSelection(selection); } } } } } void QmitkMatchPointRegistrationManipulator::OnRegSourceChanged() { this->CheckInputs(); this->ConfigureControls(); } void QmitkMatchPointRegistrationManipulator::OnNodeSelectionChanged(QList /*nodes*/) { this->CheckInputs(); this->ConfigureControls(); } void QmitkMatchPointRegistrationManipulator::NodeRemoved(const mitk::DataNode* node) { if (node == this->m_SelectedMovingNode || node == this->m_SelectedTargetNode || node == this->m_EvalNode) { if (node == this->m_EvalNode) { this->m_EvalNode = nullptr; } if (this->m_activeManipulation) { MITK_INFO << "Stopped current MatchPoint manual registration session, because at least one relevant node was removed from storage."; } this->OnCancelBtnPushed(); } } void QmitkMatchPointRegistrationManipulator::ConfigureControls() { if (!m_activeManipulation) { QString name = "ManuelRegistration"; if (m_SelectedPreRegNode.IsNotNull()) { name = QString::fromStdString(m_SelectedPreRegNode->GetName()) + " manual refined"; } this->m_Controls.lbNewRegName->setText(name); } //config settings widget this->m_Controls.groupReg->setEnabled(!m_activeManipulation); this->m_Controls.pbStart->setEnabled(this->m_SelectedMovingNode.IsNotNull() && this->m_SelectedTargetNode.IsNotNull() && !m_activeManipulation && (this->m_Controls.radioNewReg->isChecked() || this->m_SelectedPreReg.IsNotNull())); this->m_Controls.lbNewRegName->setEnabled(m_activeManipulation); this->m_Controls.checkMapEntity->setEnabled(m_activeManipulation); this->m_Controls.tabWidget->setEnabled(m_activeManipulation); this->m_Controls.pbCancel->setEnabled(m_activeManipulation); this->m_Controls.pbStore->setEnabled(m_activeManipulation); this->m_Controls.registrationNodeSelector->setEnabled(!m_activeManipulation && this->m_Controls.radioSelectedReg->isChecked()); this->m_Controls.checkAutoSelect->setEnabled(!m_activeManipulation && this->m_Controls.radioSelectedReg->isChecked()); this->m_Controls.movingNodeSelector->setEnabled(!m_activeManipulation); this->m_Controls.targetNodeSelector->setEnabled(!m_activeManipulation); } void QmitkMatchPointRegistrationManipulator::InitSession() { if (this->m_Controls.radioNewReg->isChecked()) { //init to map the image centers auto movingCenter = m_SelectedMovingNode->GetData()->GetTimeGeometry()->GetCenterInWorld(); auto targetCenter = m_SelectedTargetNode->GetData()->GetTimeGeometry()->GetCenterInWorld(); this->m_Controls.manipulationWidget->Initialize(movingCenter, targetCenter); } else { //use selected pre registration as baseline m_Controls.manipulationWidget->Initialize(m_SelectedPreReg); } this->m_CurrentRegistration = m_Controls.manipulationWidget->GetInterimRegistration(); this->m_CurrentRegistrationWrapper = mitk::MAPRegistrationWrapper::New(m_CurrentRegistration); this->m_Controls.comboCenter->setCurrentIndex(0); this->OnCenterTypeChanged(0); //reinit view - mitk::RenderingManager::GetInstance()->InitializeViews(m_SelectedTargetNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->InitializeViews(m_SelectedTargetNode->GetData()->GetTimeGeometry()); //generate evaluation node mitk::RegEvaluationObject::Pointer regEval = mitk::RegEvaluationObject::New(); regEval->SetRegistration(this->m_CurrentRegistrationWrapper); regEval->SetTargetNode(this->m_SelectedTargetNode); regEval->SetMovingNode(this->m_SelectedMovingNode); this->m_EvalNode = mitk::DataNode::New(); this->m_EvalNode->SetData(regEval); mitk::RegEvaluationMapper2D::SetDefaultProperties(this->m_EvalNode); this->m_EvalNode->SetName(HelperNodeName); this->m_EvalNode->SetBoolProperty("helper object", true); this->GetDataStorage()->Add(this->m_EvalNode); this->m_Controls.evalSettings->SetNode(this->m_EvalNode); this->m_activeManipulation = true; } void QmitkMatchPointRegistrationManipulator::StopSession() { this->m_activeManipulation = false; if (this->m_EvalNode.IsNotNull()) { this->GetDataStorage()->Remove(this->m_EvalNode); } this->m_EvalNode = nullptr; this->m_CurrentRegistration = nullptr; this->m_CurrentRegistrationWrapper = nullptr; m_Controls.manipulationWidget->Initialize(); } void QmitkMatchPointRegistrationManipulator::OnRegistrationChanged() { if (this->m_EvalNode.IsNotNull()) { this->m_EvalNode->Modified(); } if (this->m_CurrentRegistrationWrapper.IsNotNull()) { this->m_CurrentRegistrationWrapper->Modified(); } auto* renderWindowPart = this->GetRenderWindowPart(); if (nullptr != renderWindowPart) renderWindowPart->RequestUpdate(); } void QmitkMatchPointRegistrationManipulator::OnSliceChanged() { auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); auto currentSelectedPosition = renderWindowPart->GetSelectedPosition(nullptr); auto currentTimePoint = renderWindowPart->GetSelectedTimePoint(); if (m_currentSelectedPosition != currentSelectedPosition || m_currentSelectedTimePoint != currentTimePoint || m_selectedNodeTime > m_currentPositionTime) { //the current position has been changed or the selected node has been changed since the last position validation -> check position m_currentSelectedPosition = currentSelectedPosition; m_currentSelectedTimePoint = currentTimePoint; m_currentPositionTime.Modified(); if (this->m_EvalNode.IsNotNull()) { this->m_EvalNode->SetProperty(mitk::nodeProp_RegEvalCurrentPosition, mitk::Point3dProperty::New(currentSelectedPosition)); } if (m_activeManipulation && m_Controls.comboCenter->currentIndex() == 2) { //update transform with the current position. m_Controls.manipulationWidget->SetCenterOfRotation(m_currentSelectedPosition); } } } void QmitkMatchPointRegistrationManipulator::OnSettingsChanged(mitk::DataNode*) { auto* renderWindowPart = this->GetRenderWindowPart(); if (nullptr != renderWindowPart) renderWindowPart->RequestUpdate(); } void QmitkMatchPointRegistrationManipulator::OnStartBtnPushed() { this->InitSession(); this->OnSliceChanged(); auto* renderWindowPart = this->GetRenderWindowPart(); if (nullptr != renderWindowPart) renderWindowPart->RequestUpdate(); this->CheckInputs(); this->ConfigureControls(); } void QmitkMatchPointRegistrationManipulator::OnCancelBtnPushed() { this->StopSession(); this->CheckInputs(); this->ConfigureControls(); if (this->GetRenderWindowPart()) { this->GetRenderWindowPart()->RequestUpdate(); } } void QmitkMatchPointRegistrationManipulator::OnStoreBtnPushed() { map::core::RegistrationBase::Pointer newReg = this->m_Controls.manipulationWidget->GenerateRegistration(); auto newRegWrapper = mitk::MAPRegistrationWrapper::New(newReg); mitk::DataNode::Pointer spResultRegistrationNode = mitk::generateRegistrationResultNode( this->m_Controls.lbNewRegName->text().toStdString(), newRegWrapper, "org.mitk::manual_registration", mitk::EnsureUID(m_SelectedMovingNode->GetData()), mitk::EnsureUID(m_SelectedTargetNode->GetData())); this->GetDataStorage()->Add(spResultRegistrationNode); if (m_Controls.checkMapEntity->checkState() == Qt::Checked) { QmitkMappingJob* pMapJob = new QmitkMappingJob(); pMapJob->setAutoDelete(true); pMapJob->m_spInputData = this->m_SelectedMovingNode->GetData(); pMapJob->m_InputDataUID = mitk::EnsureUID(m_SelectedMovingNode->GetData()); pMapJob->m_spRegNode = spResultRegistrationNode; pMapJob->m_doGeometryRefinement = false; pMapJob->m_spRefGeometry = this->m_SelectedTargetNode->GetData()->GetGeometry()->Clone().GetPointer(); pMapJob->m_MappedName = this->m_Controls.lbNewRegName->text().toStdString() + std::string(" mapped moving data"); pMapJob->m_allowUndefPixels = true; pMapJob->m_paddingValue = 100; pMapJob->m_allowUnregPixels = true; pMapJob->m_errorValue = 200; pMapJob->m_InterpolatorLabel = "Linear Interpolation"; pMapJob->m_InterpolatorType = mitk::ImageMappingInterpolator::Linear; connect(pMapJob, SIGNAL(Error(QString)), this, SLOT(Error(QString))); connect(pMapJob, SIGNAL(MapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), this, SLOT(OnMapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), Qt::BlockingQueuedConnection); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pMapJob); } this->StopSession(); this->CheckInputs(); this->ConfigureControls(); auto* renderWindowPart = this->GetRenderWindowPart(); if (nullptr != renderWindowPart) renderWindowPart->RequestUpdate(); } void QmitkMatchPointRegistrationManipulator::OnMapResultIsAvailable(mitk::BaseData::Pointer spMappedData, const QmitkMappingJob* job) { mitk::DataNode::Pointer spMappedNode = mitk::generateMappedResultNode(job->m_MappedName, spMappedData, job->GetRegistration()->getRegistrationUID(), job->m_InputDataUID, job->m_doGeometryRefinement, job->m_InterpolatorLabel); this->GetDataStorage()->Add(spMappedNode); auto* renderWindowPart = this->GetRenderWindowPart(); if (nullptr != renderWindowPart) renderWindowPart->RequestUpdate(); } void QmitkMatchPointRegistrationManipulator::OnCenterTypeChanged(int index) { ConfigureTransformCenter(index); if (this->m_EvalNode.IsNotNull()) { this->m_EvalNode->Modified(); } if (this->m_CurrentRegistrationWrapper.IsNotNull()) { this->m_CurrentRegistrationWrapper->Modified(); } auto* renderWindowPart = this->GetRenderWindowPart(); if (nullptr != renderWindowPart) renderWindowPart->RequestUpdate(); } void QmitkMatchPointRegistrationManipulator::ConfigureTransformCenter(int centerType) { if (centerType == 0) { //image center auto center = m_SelectedMovingNode->GetData()->GetTimeGeometry()->GetCenterInWorld(); m_Controls.manipulationWidget->SetCenterOfRotationIsRelativeToTarget(false); m_Controls.manipulationWidget->SetCenterOfRotation(center); } else if (centerType == 1) { //world origin mitk::Point3D center; center.Fill(0.0); m_Controls.manipulationWidget->SetCenterOfRotationIsRelativeToTarget(false); m_Controls.manipulationWidget->SetCenterOfRotation(center); } else { //current selected point m_Controls.manipulationWidget->SetCenterOfRotationIsRelativeToTarget(true); m_Controls.manipulationWidget->SetCenterOfRotation(m_currentSelectedPosition); } } diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp index aa05008ddd..f779ae6d89 100644 --- a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp @@ -1,174 +1,174 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkMxNMultiWidgetEditor.h" #include #include #include #include #include // mxn multi widget editor plugin #include "QmitkMultiWidgetDecorationManager.h" // mitk qt widgets module #include #include #include // qt #include const QString QmitkMxNMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.mxnmultiwidget"; struct QmitkMxNMultiWidgetEditor::Impl final { Impl(); ~Impl() = default; QmitkInteractionSchemeToolBar* m_InteractionSchemeToolBar; QmitkMultiWidgetConfigurationToolBar* m_ConfigurationToolBar; }; QmitkMxNMultiWidgetEditor::Impl::Impl() : m_InteractionSchemeToolBar(nullptr) , m_ConfigurationToolBar(nullptr) { // nothing here } ////////////////////////////////////////////////////////////////////////// // QmitkMxNMultiWidgetEditor ////////////////////////////////////////////////////////////////////////// QmitkMxNMultiWidgetEditor::QmitkMxNMultiWidgetEditor() : QmitkAbstractMultiWidgetEditor() , m_Impl(std::make_unique()) { // nothing here } QmitkMxNMultiWidgetEditor::~QmitkMxNMultiWidgetEditor() { GetSite()->GetPage()->RemovePartListener(this); } void QmitkMxNMultiWidgetEditor::OnLayoutSet(int row, int column) { const auto &multiWidget = dynamic_cast(GetMultiWidget()); if (nullptr != multiWidget) { multiWidget->SetCrosshairVisibility(true); QmitkAbstractMultiWidgetEditor::OnLayoutSet(row, column); } } void QmitkMxNMultiWidgetEditor::OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) { const auto &multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return; } if (mitk::InteractionSchemeSwitcher::PACSStandard == scheme) { m_Impl->m_InteractionSchemeToolBar->setVisible(true); } else { m_Impl->m_InteractionSchemeToolBar->setVisible(false); } QmitkAbstractMultiWidgetEditor::OnInteractionSchemeChanged(scheme); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkMxNMultiWidgetEditor::SetFocus() { const auto& multiWidget = GetMultiWidget(); if (nullptr != multiWidget) { multiWidget->setFocus(); } } void QmitkMxNMultiWidgetEditor::CreateQtPartControl(QWidget* parent) { QHBoxLayout *layout = new QHBoxLayout(parent); layout->setContentsMargins(0, 0, 0, 0); berry::IBerryPreferences *preferences = dynamic_cast(GetPreferences().GetPointer()); auto multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { multiWidget = new QmitkMxNMultiWidget(parent, 0, nullptr); // create left toolbar: interaction scheme toolbar to switch how the render window navigation behaves in PACS mode if (nullptr == m_Impl->m_InteractionSchemeToolBar) { m_Impl->m_InteractionSchemeToolBar = new QmitkInteractionSchemeToolBar(parent); layout->addWidget(m_Impl->m_InteractionSchemeToolBar); } m_Impl->m_InteractionSchemeToolBar->SetInteractionEventHandler(multiWidget->GetInteractionEventHandler()); multiWidget->SetDataStorage(GetDataStorage()); multiWidget->InitializeMultiWidget(); SetMultiWidget(multiWidget); } layout->addWidget(multiWidget); // create right toolbar: configuration toolbar to change the render window widget layout if (nullptr == m_Impl->m_ConfigurationToolBar) { m_Impl->m_ConfigurationToolBar = new QmitkMultiWidgetConfigurationToolBar(multiWidget); layout->addWidget(m_Impl->m_ConfigurationToolBar); } connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::LayoutSet, this, &QmitkMxNMultiWidgetEditor::OnLayoutSet); connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::Synchronized, this, &QmitkMxNMultiWidgetEditor::OnSynchronize); connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::InteractionSchemeChanged, this, &QmitkMxNMultiWidgetEditor::OnInteractionSchemeChanged); GetSite()->GetPage()->AddPartListener(this); OnPreferencesChanged(preferences); } void QmitkMxNMultiWidgetEditor::OnPreferencesChanged(const berry::IBerryPreferences* preferences) { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return; } // update decoration preferences //m_Impl->m_MultiWidgetDecorationManager->DecorationPreferencesChanged(preferences); // zooming and panning preferences bool constrainedZooming = preferences->GetBool("Use constrained zooming and panning", true); mitk::RenderingManager::GetInstance()->SetConstrainedPanningZooming(constrainedZooming); bool PACSInteractionScheme = preferences->GetBool("PACS like mouse interaction", false); OnInteractionSchemeChanged(PACSInteractionScheme ? mitk::InteractionSchemeSwitcher::PACSStandard : mitk::InteractionSchemeSwitcher::MITKStandard); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(GetDataStorage()); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkAutocropAction.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkAutocropAction.cpp index 5cf185edc8..0e2b55a2c0 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkAutocropAction.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkAutocropAction.cpp @@ -1,192 +1,191 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkAutocropAction.h" #include "mitkAutoCropImageFilter.h" #include "mitkImageCast.h" #include "mitkImageWriteAccessor.h" #include "mitkRenderingManager.h" #include "mitkProgressBar.h" #include //needed for qApp #include QmitkAutocropAction::QmitkAutocropAction() { } QmitkAutocropAction::~QmitkAutocropAction() { } void QmitkAutocropAction::Run( const QList &selectedNodes ) { foreach ( mitk::DataNode::Pointer node, selectedNodes ) { if (node) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNull()) return; mitk::ProgressBar::GetInstance()->AddStepsToDo(10); mitk::ProgressBar::GetInstance()->Progress(2); qApp->processEvents(); mitk::AutoCropImageFilter::Pointer cropFilter = mitk::AutoCropImageFilter::New(); cropFilter->SetInput( image ); cropFilter->SetBackgroundValue( 0 ); try { cropFilter->Update(); image = cropFilter->GetOutput(); if (image.IsNotNull()) { if (image->GetDimension() == 4) { MITK_INFO << "4D AUTOCROP DOES NOT WORK AT THE MOMENT"; throw "4D AUTOCROP DOES NOT WORK AT THE MOMENT"; unsigned int timesteps = image->GetDimension(3); for (unsigned int i = 0; i < timesteps; i++) { mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(image); imageTimeSelector->SetTimeNr(i); imageTimeSelector->UpdateLargestPossibleRegion(); // We split a long nested code line into separate calls for debugging: mitk::ImageSource::OutputImageType *_3dSlice = imageTimeSelector->GetOutput(); mitk::Image::Pointer _cropped3dSlice = this->IncreaseCroppedImageSize(_3dSlice); // +++ BUG +++ BUG +++ BUG +++ BUG +++ BUG +++ BUG +++ BUG +++ mitk::ImageWriteAccessor imAccess(_cropped3dSlice); void *_data = imAccess.GetData(); // // We write some stripes into the image if ((i & 1) == 0) { int depth = _cropped3dSlice->GetDimension(2); int height = _cropped3dSlice->GetDimension(1); int width = _cropped3dSlice->GetDimension(0); for (int z = 0; z < depth; ++z) for (int y = 0; y < height; ++y) for (int x = 0; x < width; ++x) reinterpret_cast(_data)[(width * height * z) + (width * y) + x] = x & 1; // } image->SetVolume(_data, i); } node->SetData( image ); // bug fix 3145 } else { node->SetData( this->IncreaseCroppedImageSize(image) ); // bug fix 3145 } // Reinit node - mitk::RenderingManager::GetInstance()->InitializeViews( - node->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->InitializeViews(node->GetData()->GetTimeGeometry()); } } catch(...) { MITK_ERROR << "Cropping image failed..."; } mitk::ProgressBar::GetInstance()->Progress(8); } else { MITK_INFO << " a nullptr node selected"; } } } mitk::Image::Pointer QmitkAutocropAction::IncreaseCroppedImageSize( mitk::Image::Pointer image ) { typedef itk::Image< short, 3 > ImageType; typedef itk::Image< unsigned char, 3 > PADOutputImageType; ImageType::Pointer itkTransformImage = ImageType::New(); mitk::CastToItkImage( image, itkTransformImage ); typedef itk::ConstantPadImageFilter< ImageType, PADOutputImageType > PadFilterType; PadFilterType::Pointer padFilter = PadFilterType::New(); itk::SizeValueType upperPad[3]; itk::SizeValueType lowerPad[3]; int borderLiner = 3; mitk::Point3D mitkOriginPoint; double origin[3]; origin[0]=0; origin[1]=0; origin[2]=0; itkTransformImage->SetOrigin(origin); lowerPad[0]=borderLiner; lowerPad[1]=borderLiner; lowerPad[2]=borderLiner; upperPad[0]=borderLiner; upperPad[1]=borderLiner; upperPad[2]=borderLiner; padFilter->SetInput(itkTransformImage); padFilter->SetConstant(0); padFilter->SetPadUpperBound(upperPad); padFilter->SetPadLowerBound(lowerPad); padFilter->UpdateLargestPossibleRegion(); mitk::Image::Pointer paddedImage = mitk::Image::New(); paddedImage->InitializeByItk(padFilter->GetOutput()); mitk::CastToMitkImage(padFilter->GetOutput(), paddedImage); //calculate translation according to padding to get the new origin mitk::Point3D paddedOrigin = image->GetGeometry()->GetOrigin(); mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); paddedOrigin[0] -= (borderLiner)*spacing[0]; paddedOrigin[1] -= (borderLiner)*spacing[1]; paddedOrigin[2] -= (borderLiner)*spacing[2]; paddedImage->GetGeometry()->SetOrigin( paddedOrigin ); return paddedImage; } void QmitkAutocropAction::SetSmoothed(bool /*smoothed*/) { //not needed } void QmitkAutocropAction::SetDecimated(bool /*decimated*/) { //not needed } void QmitkAutocropAction::SetDataStorage(mitk::DataStorage* /*dataStorage*/) { //not needed } void QmitkAutocropAction::SetFunctionality(berry::QtViewPart* /*view*/) { //not needed } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkAutocropLabelSetImageAction.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkAutocropLabelSetImageAction.cpp index 5d4494547c..f7f5f77362 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkAutocropLabelSetImageAction.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkAutocropLabelSetImageAction.cpp @@ -1,300 +1,300 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkAutocropLabelSetImageAction.h" #include #include #include #include namespace { // Iterate over all layers, time steps, and dimensions of a LabelSetImage to // determine the overall minimum and maximum indices of labeled pixels. // // Returns false if the input image is empty, minIndex and maxIndex contain // valid indices otherwise. // // Throws an mitk::Exception if read access was denied. // bool DetermineMinimumAndMaximumIndicesOfNonBackgroundPixels(mitk::LabelSetImage::Pointer labelSetImage, itk::Index<3>& minIndex, itk::Index<3>& maxIndex) { // We need a time selector to handle 3d+t images. It is not used for 3d images, though. auto timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(labelSetImage); const auto background = labelSetImage->GetExteriorLabel()->GetValue(); const auto numLayers = labelSetImage->GetNumberOfLayers(); const auto numTimeSteps = labelSetImage->GetTimeSteps(); const itk::Index<3> dim = { labelSetImage->GetDimension(0), labelSetImage->GetDimension(1), labelSetImage->GetDimension(2) }; maxIndex = { 0, 0, 0 }; minIndex = dim; itk::Index<3> index; bool labelSetImageIsEmpty = true; for (std::remove_const_t layer = 0; layer < numLayers; ++layer) { labelSetImage->SetActiveLayer(layer); for (std::remove_const_t timeStep = 0; timeStep < numTimeSteps; ++timeStep) { const mitk::Image* image = nullptr; if (numTimeSteps > 1) { timeSelector->SetTimeNr(timeStep); timeSelector->Update(); image = timeSelector->GetOutput(); } else { image = labelSetImage; } mitk::ImagePixelReadAccessor pixelReader(image); bool imageIsEmpty = true; for (index[2] = 0; index[2] < dim[2]; ++index[2]) { for (index[1] = 0; index[1] < dim[1]; ++index[1]) { for (index[0] = 0; index[0] < dim[0]; ++index[0]) { if (background != pixelReader.GetPixelByIndex(index)) { imageIsEmpty = false; minIndex = { std::min(minIndex[0], index[0]), std::min(minIndex[1], index[1]), std::min(minIndex[2], index[2]) }; break; } } } } if (imageIsEmpty) continue; maxIndex = { std::max(maxIndex[0], minIndex[0]), std::max(maxIndex[1], minIndex[1]), std::max(maxIndex[2], minIndex[2]) }; for (index[2] = dim[2] - 1; index[2] >= 0; --index[2]) { for (index[1] = dim[1] - 1; index[1] >= 0; --index[1]) { for (index[0] = dim[0] - 1; index[0] >= 0; --index[0]) { if (background != pixelReader.GetPixelByIndex(index)) { maxIndex = { std::max(maxIndex[0], index[0]), std::max(maxIndex[1], index[1]), std::max(maxIndex[2], index[2]) }; break; } } } } if (!imageIsEmpty) labelSetImageIsEmpty = false; } } return !labelSetImageIsEmpty; } // Crop a LabelSetImage. Labels in the cropped LabelSetImage will still have // their original properties like names and colors. // // Returns a cropped LabelSetImage. // // Throws an mitk::Exception if read access was denied. // mitk::LabelSetImage::Pointer Crop(mitk::LabelSetImage::Pointer labelSetImage, const itk::Index<3>& minIndex, const itk::Index<3>& maxIndex) { // We need a time selector to handle 3d+t images. It is not used for 3d images, though. auto timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(labelSetImage); const auto numLayers = labelSetImage->GetNumberOfLayers(); const auto numTimeSteps = labelSetImage->GetTimeSteps(); const itk::Index<3> croppedDim = { 1 + maxIndex[0] - minIndex[0], 1 + maxIndex[1] - minIndex[1], 1 + maxIndex[2] - minIndex[2] }; const auto numPixels = croppedDim[0] * croppedDim[1] * croppedDim[2]; mitk::BaseGeometry::BoundsArrayType croppedBounds; croppedBounds[0] = 0; croppedBounds[1] = croppedDim[0]; croppedBounds[2] = 0; croppedBounds[3] = croppedDim[1]; croppedBounds[4] = 0; croppedBounds[5] = croppedDim[2]; // Clone and adapt the original TimeGeometry to the cropped region auto croppedTimeGeometry = labelSetImage->GetTimeGeometry()->Clone(); for (std::remove_const_t timeStep = 0; timeStep < numTimeSteps; ++timeStep) { auto geometry = croppedTimeGeometry->GetGeometryForTimeStep(timeStep); mitk::Point3D croppedOrigin; geometry->IndexToWorld(minIndex, croppedOrigin); geometry->SetOrigin(croppedOrigin); geometry->SetBounds(croppedBounds); } auto croppedLabelSetImage = mitk::LabelSetImage::New(); croppedLabelSetImage->Initialize(mitk::MakeScalarPixelType(), *croppedTimeGeometry); // Create cropped image volumes for all time steps in all layers for (std::remove_const_t layer = 0; layer < numLayers; ++layer) { labelSetImage->SetActiveLayer(layer); croppedLabelSetImage->AddLayer(); for (std::remove_const_t timeStep = 0; timeStep < numTimeSteps; ++timeStep) { const mitk::Image* image = nullptr; if (numTimeSteps > 1) { timeSelector->SetTimeNr(timeStep); timeSelector->Update(); image = timeSelector->GetOutput(); } else { image = labelSetImage; } mitk::ImagePixelReadAccessor pixelReader(image); auto* croppedVolume = new mitk::LabelSetImage::PixelType[numPixels]; itk::Index<3> croppedIndex; itk::Index<3> index; for (croppedIndex[2] = 0; croppedIndex[2] < croppedDim[2]; ++croppedIndex[2]) { for (croppedIndex[1] = 0; croppedIndex[1] < croppedDim[1]; ++croppedIndex[1]) { for (croppedIndex[0] = 0; croppedIndex[0] < croppedDim[0]; ++croppedIndex[0]) { index[0] = croppedIndex[0] + minIndex[0]; index[1] = croppedIndex[1] + minIndex[1]; index[2] = croppedIndex[2] + minIndex[2]; const auto& pixel = pixelReader.GetPixelByIndex(index); croppedVolume[croppedIndex[2] * croppedDim[1] * croppedDim[0] + croppedIndex[1] * croppedDim[0] + croppedIndex[0]] = pixel; } } } croppedLabelSetImage->SetImportVolume(croppedVolume, timeStep, 0, mitk::Image::ReferenceMemory); croppedLabelSetImage->AddLabelSetToLayer(layer, labelSetImage->GetLabelSet(layer)); } } return croppedLabelSetImage; } } QmitkAutocropLabelSetImageAction::QmitkAutocropLabelSetImageAction() { } QmitkAutocropLabelSetImageAction::~QmitkAutocropLabelSetImageAction() { } void QmitkAutocropLabelSetImageAction::Run(const QList& selectedNodes) { for (const auto& dataNode : selectedNodes) { mitk::LabelSetImage::Pointer labelSetImage = dynamic_cast(dataNode->GetData()); if (labelSetImage.IsNull()) continue; // Backup currently active layer as we need to restore it later auto activeLayer = labelSetImage->GetActiveLayer(); mitk::LabelSetImage::Pointer croppedLabelSetImage; itk::Index<3> minIndex; itk::Index<3> maxIndex; try { if (!DetermineMinimumAndMaximumIndicesOfNonBackgroundPixels(labelSetImage, minIndex, maxIndex)) { MITK_WARN << "Autocrop was skipped: Image \"" << dataNode->GetName() << "\" is empty."; labelSetImage->SetActiveLayer(activeLayer); // Restore the originally active layer return; } croppedLabelSetImage = Crop(labelSetImage, minIndex, maxIndex); } catch (const mitk::Exception&) { MITK_ERROR << "Autocrop was aborted: Image read access to \"" << dataNode->GetName() << "\" was denied."; labelSetImage->SetActiveLayer(activeLayer); // Restore the originally active layer return; } // Restore the originally active layer in the cropped LabelSetImage croppedLabelSetImage->SetActiveLayer(activeLayer); // Override the original LabelSetImage with the cropped LabelSetImage dataNode->SetData(croppedLabelSetImage); // If we cropped a single LabelSetImage, reinit the views to give a visible feedback to the user if (1 == selectedNodes.size()) - mitk::RenderingManager::GetInstance()->InitializeViews(croppedLabelSetImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->InitializeViews(croppedLabelSetImage->GetTimeGeometry()); } } void QmitkAutocropLabelSetImageAction::SetSmoothed(bool) { } void QmitkAutocropLabelSetImageAction::SetDecimated(bool) { } void QmitkAutocropLabelSetImageAction::SetDataStorage(mitk::DataStorage*) { } void QmitkAutocropLabelSetImageAction::SetFunctionality(berry::QtViewPart*) { } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkCreatePolygonModelAction.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkCreatePolygonModelAction.cpp index 16b6eaa977..54c3c99e6d 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkCreatePolygonModelAction.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkCreatePolygonModelAction.cpp @@ -1,135 +1,134 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkCreatePolygonModelAction.h" // MITK #include #include #include #include #include -#include // Blueberry #include #include #include #include using namespace berry; using namespace mitk; using namespace std; QmitkCreatePolygonModelAction::QmitkCreatePolygonModelAction() { } QmitkCreatePolygonModelAction::~QmitkCreatePolygonModelAction() { } void QmitkCreatePolygonModelAction::Run(const QList &selectedNodes) { DataNode::Pointer selectedNode = selectedNodes[0]; Image::Pointer image = dynamic_cast(selectedNode->GetData()); if (image.IsNull()) { return; } try { // Get preference properties for smoothing and decimation IPreferencesService* prefService = Platform::GetPreferencesService(); IPreferences::Pointer segPref = prefService->GetSystemPreferences()->Node("/org.mitk.views.segmentation"); bool smoothingHint = segPref->GetBool("smoothing hint", true); ScalarType smoothing = segPref->GetDouble("smoothing value", 1.0); ScalarType decimation = segPref->GetDouble("decimation rate", 0.5); if (smoothingHint) { smoothing = 0.0; Vector3D spacing = image->GetGeometry()->GetSpacing(); for (Vector3D::Iterator iter = spacing.Begin(); iter != spacing.End(); ++iter) smoothing = max(smoothing, *iter); } ShowSegmentationAsSurface::Pointer surfaceFilter = ShowSegmentationAsSurface::New(); // Activate callback functions itk::SimpleMemberCommand::Pointer successCommand = itk::SimpleMemberCommand::New(); successCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); surfaceFilter->AddObserver(ResultAvailable(), successCommand); itk::SimpleMemberCommand::Pointer errorCommand = itk::SimpleMemberCommand::New(); errorCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); surfaceFilter->AddObserver(ProcessingError(), errorCommand); // set filter parameter surfaceFilter->SetDataStorage(*m_DataStorage); surfaceFilter->SetPointerParameter("Input", image); surfaceFilter->SetPointerParameter("Group node", selectedNode); surfaceFilter->SetParameter("Show result", true); surfaceFilter->SetParameter("Sync visibility", false); surfaceFilter->SetParameter("Median kernel size", 3u); surfaceFilter->SetParameter("Decimate mesh", m_IsDecimated); surfaceFilter->SetParameter("Decimation rate", decimation); if (m_IsSmoothed) { surfaceFilter->SetParameter("Apply median", true); surfaceFilter->SetParameter("Smooth", true); surfaceFilter->SetParameter("Gaussian SD", sqrt(smoothing)); // use sqrt to account for setting of variance in preferences StatusBar::GetInstance()->DisplayText("Smoothed surface creation started in background..."); } else { surfaceFilter->SetParameter("Apply median", false); surfaceFilter->SetParameter("Smooth", false); StatusBar::GetInstance()->DisplayText("Surface creation started in background..."); } surfaceFilter->StartAlgorithm(); } catch(...) { MITK_ERROR << "Surface creation failed!"; } } void QmitkCreatePolygonModelAction::OnSurfaceCalculationDone() { StatusBar::GetInstance()->Clear(); } void QmitkCreatePolygonModelAction::SetDataStorage(DataStorage *dataStorage) { m_DataStorage = dataStorage; } void QmitkCreatePolygonModelAction::SetSmoothed(bool smoothed) { m_IsSmoothed = smoothed; } void QmitkCreatePolygonModelAction::SetDecimated(bool decimated) { m_IsDecimated = decimated; } void QmitkCreatePolygonModelAction::SetFunctionality(QtViewPart *) { } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp index 665a4ab08a..b6e9ce7db4 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp @@ -1,281 +1,281 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // semantic relations plugin #include "QmitkSemanticRelationsView.h" #include "QmitkDataNodeAddToSemanticRelationsAction.h" #include "QmitkDataNodeRemoveFromSemanticRelationsAction.h" #include "QmitkLabelSetJumpToAction.h" // semantic relations module #include #include #include #include #include // mitk core #include // mitk qt widgets module #include #include // berry #include #include // qt #include #include #include const std::string QmitkSemanticRelationsView::VIEW_ID = "org.mitk.views.semanticrelations"; void QmitkSemanticRelationsView::SetFocus() { // nothing here } void QmitkSemanticRelationsView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; SetControlledRenderer(); } } void QmitkSemanticRelationsView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart == renderWindowPart) { m_RenderWindowPart = nullptr; SetControlledRenderer(); } } void QmitkSemanticRelationsView::RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart == renderWindowPart) { SetControlledRenderer(); } } void QmitkSemanticRelationsView::CreateQtPartControl(QWidget* parent) { // create GUI widgets m_Controls.setupUi(parent); m_LesionInfoWidget = new QmitkLesionInfoWidget(GetDataStorage(), GetSite(), parent); m_Controls.gridLayout->addWidget(m_LesionInfoWidget); m_PatientTableInspector = new QmitkPatientTableInspector(parent); m_PatientTableInspector->SetDataStorage(GetDataStorage()); m_Controls.gridLayout->addWidget(m_PatientTableInspector); QGridLayout* dndDataNodeWidgetLayout = new QGridLayout; dndDataNodeWidgetLayout->addWidget(m_PatientTableInspector, 0, 0); dndDataNodeWidgetLayout->setContentsMargins(0, 0, 0, 0); m_DnDDataNodeWidget = new QmitkDnDDataNodeWidget(parent); m_DnDDataNodeWidget->setLayout(dndDataNodeWidgetLayout); m_Controls.gridLayout->addWidget(m_DnDDataNodeWidget); m_ContextMenu = new QmitkSemanticRelationsContextMenu(GetSite(), m_PatientTableInspector); m_ContextMenu->SetDataStorage(GetDataStorage()); mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); if (nullptr != renderWindowPart) { RenderWindowPartActivated(renderWindowPart); } SetUpConnections(); const auto& allCaseIDs = mitk::RelationStorage::GetAllCaseIDs(); for (const auto& caseID : allCaseIDs) { AddToComboBox(caseID); } } void QmitkSemanticRelationsView::SetUpConnections() { connect(m_Controls.caseIDComboBox, static_cast(&QComboBox::currentIndexChanged), this, &QmitkSemanticRelationsView::OnCaseIDSelectionChanged); connect(m_LesionInfoWidget, &QmitkLesionInfoWidget::LesionSelectionChanged, this, &QmitkSemanticRelationsView::OnLesionSelectionChanged); connect(m_PatientTableInspector, &QmitkPatientTableInspector::CurrentSelectionChanged, this, &QmitkSemanticRelationsView::OnDataNodeSelectionChanged); connect(m_PatientTableInspector, &QmitkPatientTableInspector::DataNodeDoubleClicked, this, &QmitkSemanticRelationsView::OnDataNodeDoubleClicked); connect(m_DnDDataNodeWidget, &QmitkDnDDataNodeWidget::NodesDropped, this, &QmitkSemanticRelationsView::OnNodesAdded); connect(m_PatientTableInspector, &QmitkPatientTableInspector::OnContextMenuRequested, m_ContextMenu, &QmitkSemanticRelationsContextMenu::OnContextMenuRequested); connect(m_PatientTableInspector, &QmitkPatientTableInspector::OnNodeRemoved, this, &QmitkSemanticRelationsView::NodeRemoved); } QItemSelectionModel* QmitkSemanticRelationsView::GetDataNodeSelectionModel() const { return m_PatientTableInspector->GetSelectionModel(); } void QmitkSemanticRelationsView::NodeRemoved(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } if (mitk::SemanticRelationsInference::InstanceExists(dataNode)) { try { RemoveFromSemanticRelationsAction::Run(GetDataStorage(), dataNode); mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(dataNode); RemoveFromComboBox(caseID); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; QMessageBox msgBox(QMessageBox::Warning, "Could not remove the data node(s).", "The program wasn't able to correctly remove the selected data node(s).\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str() + "\n")); msgBox.exec(); } } } void QmitkSemanticRelationsView::OnLesionSelectionChanged(const mitk::SemanticTypes::Lesion& lesion) { m_PatientTableInspector->SetLesion(lesion); } void QmitkSemanticRelationsView::OnDataNodeSelectionChanged(const QList& dataNodeSelection) { m_LesionInfoWidget->SetDataNodeSelection(dataNodeSelection); } void QmitkSemanticRelationsView::OnDataNodeDoubleClicked(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) { OpenInEditor(dataNode); } else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) { LabelSetJumpToAction::Run(GetSite(), dataNode); } } void QmitkSemanticRelationsView::OnCaseIDSelectionChanged(const QString& caseID) { m_LesionInfoWidget->SetCaseID(caseID.toStdString()); m_PatientTableInspector->SetCaseID(caseID.toStdString()); } void QmitkSemanticRelationsView::OnNodesAdded(std::vector nodes) { mitk::SemanticTypes::CaseID caseID = ""; for (mitk::DataNode* dataNode : nodes) { try { AddToSemanticRelationsAction::Run(GetDataStorage(), dataNode); caseID = mitk::GetCaseIDFromDataNode(dataNode); AddToComboBox(caseID); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; QMessageBox msgBox(QMessageBox::Warning, "Could not add the data node(s).", "The program wasn't able to correctly add the selected data node(s).\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str() + "\n")); msgBox.exec(); } } } void QmitkSemanticRelationsView::OnNodeRemoved(const mitk::DataNode* dataNode) { NodeRemoved(dataNode); } void QmitkSemanticRelationsView::AddToComboBox(const mitk::SemanticTypes::CaseID& caseID) { int foundIndex = m_Controls.caseIDComboBox->findText(QString::fromStdString(caseID)); if (-1 == foundIndex) { // add the caseID to the combo box, as it is not already contained m_Controls.caseIDComboBox->addItem(QString::fromStdString(caseID)); } } void QmitkSemanticRelationsView::RemoveFromComboBox(const mitk::SemanticTypes::CaseID& caseID) { std::vector allControlPoints = mitk::RelationStorage::GetAllControlPointsOfCase(caseID); int foundIndex = m_Controls.caseIDComboBox->findText(QString::fromStdString(caseID)); if (allControlPoints.empty() && -1 != foundIndex) { // caseID does not contain any control points and therefore no data // remove the caseID, if it is still contained m_Controls.caseIDComboBox->removeItem(foundIndex); } } void QmitkSemanticRelationsView::OpenInEditor(const mitk::DataNode* dataNode) { auto renderWindowPart = GetRenderWindowPart(); if (nullptr == renderWindowPart) { renderWindowPart = GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::BRING_TO_FRONT | mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); if (nullptr == renderWindowPart) { // no render window available return; } } auto image = dynamic_cast(dataNode->GetData()); if (nullptr != image) { - mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry()); } } void QmitkSemanticRelationsView::SetControlledRenderer() { QHash renderWindows; if (m_RenderWindowPart != nullptr) { renderWindows = m_RenderWindowPart->GetQmitkRenderWindows(); } mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer; mitk::BaseRenderer* baseRenderer = nullptr; for (const auto& renderWindow : renderWindows.values()) { baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow->GetVtkRenderWindow()); if (nullptr != baseRenderer) { controlledRenderer.push_back(baseRenderer); } } m_ContextMenu->SetControlledRenderer(controlledRenderer); } diff --git a/Plugins/org.mitk.gui.qt.toftutorial/src/internal/QmitkToFTutorialView.cpp b/Plugins/org.mitk.gui.qt.toftutorial/src/internal/QmitkToFTutorialView.cpp index c2984e620e..df84b6959b 100644 --- a/Plugins/org.mitk.gui.qt.toftutorial/src/internal/QmitkToFTutorialView.cpp +++ b/Plugins/org.mitk.gui.qt.toftutorial/src/internal/QmitkToFTutorialView.cpp @@ -1,183 +1,182 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkToFTutorialView.h" // Qt #include // mitk includes #include // class holding the intrinsic parameters of the according camera #include // MITK-ToF related includes #include #include // configuration file holding e.g. plugin paths or path to test file directory #include // filter from module ToFProcessing that calculates a surface from the given range image #include // allows access to images provided by the ToF camera const std::string QmitkToFTutorialView::VIEW_ID = "org.mitk.views.toftutorial"; QmitkToFTutorialView::QmitkToFTutorialView() : QmitkAbstractView() , m_Controls( nullptr ) { } QmitkToFTutorialView::~QmitkToFTutorialView() { } void QmitkToFTutorialView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkToFTutorialViewControls; m_Controls->setupUi( parent ); connect( m_Controls->step1Button, SIGNAL(clicked()), this, SLOT(OnStep1()) ); connect( m_Controls->step2Button, SIGNAL(clicked()), this, SLOT(OnStep2()) ); } } void QmitkToFTutorialView::SetFocus() { m_Controls->step1Button->setFocus(); } void QmitkToFTutorialView::OnStep1() { // clean up data storage RemoveAllNodesFromDataStorage(); // Create an instance of ToFImageGrabber that holds a ToFCameraMITKPlayerDevice for playing ToF data mitk::ToFImageGrabber::Pointer tofImageGrabber = mitk::ToFImageGrabber::New(); tofImageGrabber->SetCameraDevice(mitk::ToFCameraMITKPlayerDevice::New()); // set paths to test data std::string distanceFileName = MITK_TOF_DATA_DIR; distanceFileName.append("/PMDCamCube2_MF0_IT0_20Images_DistanceImage.nrrd"); std::string amplitudeFileName = MITK_TOF_DATA_DIR; amplitudeFileName.append("/PMDCamCube2_MF0_IT0_20Images_AmplitudeImage.nrrd"); std::string intensityFileName = MITK_TOF_DATA_DIR; intensityFileName.append("/PMDCamCube2_MF0_IT0_20Images_IntensityImage.nrrd"); // set file name property in image grabber. This will be propagated to the corresponding device and controller class tofImageGrabber->SetProperty("DistanceImageFileName",mitk::StringProperty::New(distanceFileName)); tofImageGrabber->SetProperty("AmplitudeImageFileName",mitk::StringProperty::New(amplitudeFileName)); tofImageGrabber->SetProperty("IntensityImageFileName",mitk::StringProperty::New(intensityFileName)); // connect to device if (tofImageGrabber->ConnectCamera()) { //// start camera (internally starts thread that continuously grabs images from the camera) tofImageGrabber->StartCamera(); // update image grabber which itself represents the source of a MITK filter pipeline tofImageGrabber->Update(); // grab distance image mitk::Image::Pointer distanceImage = tofImageGrabber->GetOutput(); // grab amplitude image mitk::Image::Pointer amplitudeImage = tofImageGrabber->GetOutput(1); // grab intensity image mitk::Image::Pointer intensityImage = tofImageGrabber->GetOutput(2); //add distance image to data storage mitk::DataNode::Pointer distanceNode = mitk::DataNode::New(); distanceNode->SetName("Distance Image"); distanceNode->SetData(distanceImage); this->GetDataStorage()->Add(distanceNode); //add amplitude image to data storage mitk::DataNode::Pointer amplitudeNode = mitk::DataNode::New(); amplitudeNode->SetName("Amplitude Image"); amplitudeNode->SetData(amplitudeImage); this->GetDataStorage()->Add(amplitudeNode); //add intensity image to data storage mitk::DataNode::Pointer intensityNode = mitk::DataNode::New(); intensityNode->SetName("Intensity Image"); intensityNode->SetData(intensityImage); this->GetDataStorage()->Add(intensityNode); // stop camera (terminate internally used thread) tofImageGrabber->StopCamera(); //// disconnect from camera tofImageGrabber->DisconnectCamera(); // adjust views to new data in DataStorage mitk::RenderingManager::GetInstance()->InitializeViews(distanceImage->GetGeometry()); } else { MITK_ERROR<<"Connection to ToF camera could not be established"; } } void QmitkToFTutorialView::OnStep2() { // Check if distance image is available mitk::DataNode::Pointer distanceNode = this->GetDataStorage()->GetNamedNode("Distance Image"); if (distanceNode.IsNotNull()) { // get distance image from node and check if node contains image mitk::Image::Pointer distanceImage = dynamic_cast(distanceNode->GetData()); if (distanceImage.IsNotNull()) { // create object of CameraIntrinsics that holds intrinsic parameters of the ToF camera mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); // set focal length in pixel cameraIntrinsics->SetFocalLength(295.8,296.1); // set principal point in pixel cameraIntrinsics->SetPrincipalPoint(113.2,97.1); // set up filter for surface calculation mitk::ToFDistanceImageToSurfaceFilter::Pointer surfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); // apply intrinsic parameters to filter surfaceFilter->SetCameraIntrinsics(cameraIntrinsics); // set distance between pixels on chip in mm (in this example squared pixel) mitk::ToFProcessingCommon::ToFPoint2D interPixelDistance; interPixelDistance[0] = 0.045; interPixelDistance[1] = 0.045; surfaceFilter->SetInterPixelDistance(interPixelDistance); // set distance image as input surfaceFilter->SetInput(distanceImage); // update the filter surfaceFilter->Update(); // get surface from filter mitk::Surface::Pointer surface = surfaceFilter->GetOutput(); // add surface to data storage mitk::DataNode::Pointer surfaceNode = mitk::DataNode::New(); surfaceNode->SetName("ToF surface"); surfaceNode->SetData(surface); this->GetDataStorage()->Add(surfaceNode); // adjust views to new data in DataStorage mitk::RenderingManager::GetInstance()->InitializeViews(surface->GetGeometry()); - mitk::RenderingManager::GetInstance()->InitializeViews(surface->GetGeometry()); } else { QMessageBox::warning(nullptr,"ToF Tutorial","Node 'Distance Image' contains no image"); } } else { QMessageBox::warning(nullptr,"ToF Tutorial","Perform Step 1 first to acquire a distance image"); } } void QmitkToFTutorialView::RemoveAllNodesFromDataStorage() { mitk::DataStorage::SetOfObjects::ConstPointer allNodes = this->GetDataStorage()->GetAll(); this->GetDataStorage()->Remove(allNodes); } diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp index 92920c9c2f..53e1d71327 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp @@ -1,535 +1,536 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ + // Blueberry -#include #include #include // Qmitk #include "QmitkToFUtilView.h" // Qt #include #include #include #include #include // MITK #include #include #include #include #include #include #include #include #include #include // VTK #include #include #include // ITK #include #include const std::string QmitkToFUtilView::VIEW_ID = "org.mitk.views.tofutil"; //Constructor QmitkToFUtilView::QmitkToFUtilView() : QmitkAbstractView() , m_Controls(nullptr) , m_Framerateoutput(false) , m_MitkDistanceImage(nullptr), m_MitkAmplitudeImage(nullptr), m_MitkIntensityImage(nullptr), m_Surface(nullptr) , m_DistanceImageNode(nullptr), m_AmplitudeImageNode(nullptr), m_IntensityImageNode(nullptr), m_RGBImageNode(nullptr), m_SurfaceNode(nullptr) , m_ToFImageRecorder(nullptr), m_ToFImageGrabber(nullptr), m_ToFDistanceImageToSurfaceFilter(nullptr), m_ToFCompositeFilter(nullptr) , m_2DDisplayCount(0) , m_RealTimeClock(nullptr) , m_StepsForFramerate(100) , m_2DTimeBefore(0.0) , m_2DTimeAfter(0.0) , m_CameraIntrinsics(nullptr) { this->m_Frametimer = new QTimer(this); this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); } //Destructor, specifically calling OnToFCameraStopped() and OnToFCammeraDiconnected() QmitkToFUtilView::~QmitkToFUtilView() { OnToFCameraStopped(); OnToFCameraDisconnected(); } //Createing the PartControl Signal-Slot principal void QmitkToFUtilView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkToFUtilViewControls; m_Controls->setupUi( parent ); //Looking for Input and Defining reaction connect(m_Frametimer, SIGNAL(timeout()), this, SLOT(OnUpdateCamera())); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(KinectAcquisitionModeChanged()), this, SLOT(OnKinectAcquisitionModeChanged()) ); // Todo in Widget2 connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraConnected()), this, SLOT(OnToFCameraConnected()) ); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraDisconnected()), this, SLOT(OnToFCameraDisconnected()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStarted()), this, SLOT(OnToFCameraStarted()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStopped()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStarted()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStopped()), this, SLOT(OnToFCameraStarted()) ); } } //SetFocus-Method -> actually seting Focus to the Recorder void QmitkToFUtilView::SetFocus() { m_Controls->m_ToFRecorderWidget->setFocus(); } //Activated-Method->Generating RenderWindow void QmitkToFUtilView::Activated() { //get the current RenderWindowPart or open a new one if there is none auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); if (nullptr != renderWindowPart) { auto* linkedRenderWindowPart = dynamic_cast(renderWindowPart); if (linkedRenderWindowPart == nullptr) { MITK_ERROR << "No linked render window part avaiable!!!"; } else { linkedRenderWindowPart->EnableSlicingPlanes(false); } renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOn(); renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOn(); renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOn(); mitk::RenderingManager::GetInstance()->InitializeViews(); this->UseToFVisibilitySettings(true); if (this->m_ToFCompositeFilter) { m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); } if (this->GetDataStorage()) { m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); } if (this->m_ToFImageGrabber.IsNull()) { m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); m_Controls->m_ToFMeasurementWidget->setEnabled(false); m_Controls->m_ToFSurfaceGenerationWidget->setEnabled(false); } } } //ZomnnieView-Method -> Resetting GUI to default. Why not just QmitkToFUtilView()?! void QmitkToFUtilView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer /*zombieView*/) { ResetGUIToDefault(); } void QmitkToFUtilView::Deactivated() { } void QmitkToFUtilView::Visible() { } //Reset of the ToFUtilView void QmitkToFUtilView::Hidden() { ResetGUIToDefault(); } void QmitkToFUtilView::OnToFCameraConnected() { MITK_DEBUG <<"OnToFCameraConnected"; this->m_2DDisplayCount = 0; this->m_ToFImageGrabber = m_Controls->m_ToFConnectionWidget->GetToFImageGrabber(); // initialize surface generation this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); // initialize ToFImageRecorder and ToFRecorderWidget this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); this->m_ToFImageRecorder->SetCameraDevice(this->m_ToFImageGrabber->GetCameraDevice()); m_Controls->m_ToFRecorderWidget->SetParameter(this->m_ToFImageGrabber, this->m_ToFImageRecorder); m_Controls->m_ToFRecorderWidget->setEnabled(true); m_Controls->m_ToFRecorderWidget->ResetGUIToInitial(); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); // initialize ToFCompositeFilterWidget this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); if (this->m_ToFCompositeFilter) { m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); } if (this->GetDataStorage()) { m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); } if ( this->GetRenderWindowPart() ) // initialize measurement widget m_Controls->m_ToFMeasurementWidget->InitializeWidget(this->GetRenderWindowPart()->GetQmitkRenderWindows(),this->GetDataStorage(), this->m_ToFDistanceImageToSurfaceFilter->GetCameraIntrinsics()); else MITK_WARN << "No render window part available!!! MeasurementWidget will not work."; this->m_RealTimeClock = mitk::RealTimeClock::New(); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); this->RequestRenderWindowUpdate(); } void QmitkToFUtilView::ResetGUIToDefault() { auto* renderWindowPart = this->GetRenderWindowPart(); if(nullptr != renderWindowPart) { auto* linkedRenderWindowPart = dynamic_cast(renderWindowPart); if(linkedRenderWindowPart == nullptr) { MITK_ERROR << "No linked render window part avaiable!!!"; } else { linkedRenderWindowPart->EnableSlicingPlanes(true); } renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOff(); renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOff(); renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOff(); this->UseToFVisibilitySettings(false); //global reinit mitk::RenderingManager::GetInstance()->InitializeViews(); this->RequestRenderWindowUpdate(); } } void QmitkToFUtilView::OnToFCameraDisconnected() { this->GetDataStorage()->Remove(m_DistanceImageNode); if(m_RGBImageNode) this->GetDataStorage()->Remove(m_RGBImageNode); if(m_AmplitudeImageNode) this->GetDataStorage()->Remove(m_AmplitudeImageNode); if(m_IntensityImageNode) this->GetDataStorage()->Remove(m_IntensityImageNode); if(m_SurfaceNode) this->GetDataStorage()->Remove(m_SurfaceNode); m_Controls->m_ToFRecorderWidget->OnStop(); m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); m_Controls->m_ToFMeasurementWidget->setEnabled(false); m_Controls->m_ToFSurfaceGenerationWidget->setEnabled(false); //clean up measurement widget m_Controls->m_ToFMeasurementWidget->CleanUpWidget(); } void QmitkToFUtilView::OnKinectAcquisitionModeChanged() { if (m_ToFCompositeFilter.IsNotNull()&&m_ToFImageGrabber.IsNotNull()) { if (m_SelectedCamera.contains("Kinect")) { if (m_ToFImageGrabber->GetBoolProperty("RGB")) { this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); this->m_ToFDistanceImageToSurfaceFilter->SetInput(3,this->m_ToFImageGrabber->GetOutput(3)); } else if (m_ToFImageGrabber->GetBoolProperty("IR")) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); } } this->UseToFVisibilitySettings(true); } } void QmitkToFUtilView::OnToFCameraStarted() { if (m_ToFImageGrabber.IsNotNull()) { // initialize camera intrinsics if (this->m_ToFImageGrabber->GetProperty("CameraIntrinsics")) { m_CameraIntrinsics = dynamic_cast(this->m_ToFImageGrabber->GetProperty("CameraIntrinsics"))->GetValue(); MITK_INFO << m_CameraIntrinsics->ToString(); } else { m_CameraIntrinsics = nullptr; MITK_ERROR << "No camera intrinsics were found!"; } // set camera intrinsics if ( m_CameraIntrinsics.IsNotNull() ) { this->m_ToFDistanceImageToSurfaceFilter->SetCameraIntrinsics(m_CameraIntrinsics); } // initial update of image grabber this->m_ToFImageGrabber->Update(); bool hasRGBImage = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasRGBImage",hasRGBImage); bool hasIntensityImage = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasIntensityImage",hasIntensityImage); bool hasAmplitudeImage = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasAmplitudeImage",hasAmplitudeImage); this->m_ToFCompositeFilter->SetInput(0,this->m_ToFImageGrabber->GetOutput(0)); if(hasAmplitudeImage) this->m_ToFCompositeFilter->SetInput(1,this->m_ToFImageGrabber->GetOutput(1)); if(hasIntensityImage) this->m_ToFCompositeFilter->SetInput(2,this->m_ToFImageGrabber->GetOutput(2)); // initial update of composite filter this->m_ToFCompositeFilter->Update(); this->m_MitkDistanceImage = m_ToFCompositeFilter->GetOutput(); this->m_DistanceImageNode = ReplaceNodeData("Distance image",m_MitkDistanceImage); std::string rgbFileName; m_ToFImageGrabber->GetCameraDevice()->GetStringProperty("RGBImageFileName",rgbFileName); if(hasRGBImage || (rgbFileName!="")) { if(m_ToFImageGrabber->GetBoolProperty("IR")) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); } else { this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); } } else { this->m_RGBImageNode = nullptr; } if(hasAmplitudeImage) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); } if(hasIntensityImage) { this->m_MitkIntensityImage = m_ToFCompositeFilter->GetOutput(2); this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); } this->m_ToFDistanceImageToSurfaceFilter->SetInput(0,m_MitkDistanceImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(1,m_MitkAmplitudeImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(2,m_MitkIntensityImage); this->UseToFVisibilitySettings(true); this->m_SurfaceNode = ReplaceNodeData("Surface", nullptr); m_Controls->m_ToFCompositeFilterWidget->UpdateFilterParameter(); // initialize visualization widget m_Controls->m_ToFVisualisationSettingsWidget->Initialize(this->m_DistanceImageNode, this->m_AmplitudeImageNode, this->m_IntensityImageNode, this->m_SurfaceNode); m_Controls->m_ToFSurfaceGenerationWidget->Initialize(m_ToFDistanceImageToSurfaceFilter, m_ToFImageGrabber, m_CameraIntrinsics, m_SurfaceNode, GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("3d")->GetRenderer()->GetVtkRenderer()->GetActiveCamera()); // set distance image to measurement widget m_Controls->m_ToFMeasurementWidget->SetDistanceImage(m_MitkDistanceImage); this->m_Frametimer->start(50); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(true); m_Controls->m_ToFCompositeFilterWidget->setEnabled(true); m_Controls->m_ToFMeasurementWidget->setEnabled(true); m_Controls->m_ToFSurfaceGenerationWidget->setEnabled(true); } } void QmitkToFUtilView::OnToFCameraStopped() { m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); this->m_Frametimer->stop(); } void QmitkToFUtilView::OnUpdateCamera() { if(!m_Controls->m_ToFSurfaceGenerationWidget->UpdateSurface()) { // update pipeline this->m_MitkDistanceImage->Update(); } this->RequestRenderWindowUpdate(); if (m_Framerateoutput) { this->m_2DDisplayCount++; if ((this->m_2DDisplayCount % this->m_StepsForFramerate) == 0) { this->m_2DTimeAfter = this->m_RealTimeClock->GetCurrentStamp() - this->m_2DTimeBefore; MITK_INFO << " 2D-Display-framerate (fps): " << this->m_StepsForFramerate / (this->m_2DTimeAfter / 1000); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); } } } void QmitkToFUtilView::OnChangeCoronalWindowOutput(int index) { this->OnToFCameraStopped(); if(index == 0) { if(this->m_IntensityImageNode.IsNotNull()) this->m_IntensityImageNode->SetVisibility(false); if(this->m_RGBImageNode.IsNotNull()) this->m_RGBImageNode->SetVisibility(true); } else if(index == 1) { if(this->m_IntensityImageNode.IsNotNull()) this->m_IntensityImageNode->SetVisibility(true); if(this->m_RGBImageNode.IsNotNull()) this->m_RGBImageNode->SetVisibility(false); } this->RequestRenderWindowUpdate(); this->OnToFCameraStarted(); } mitk::DataNode::Pointer QmitkToFUtilView::ReplaceNodeData( std::string nodeName, mitk::BaseData* data ) { mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(nodeName); if (node.IsNull()) { node = mitk::DataNode::New(); node->SetName(nodeName); node->SetBoolProperty("binary",false); node->SetData(data); this->GetDataStorage()->Add(node); } else { node->SetData(data); } return node; } void QmitkToFUtilView::UseToFVisibilitySettings(bool useToF) { //We need this property for every node. auto renderingModePropertyForTransferFunction = mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR); auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); auto* axialRenderer = mitk::BaseRenderer::GetInstance(renderWindowPart->GetQmitkRenderWindow("axial")->renderWindow()); auto* sagittalRenderer = mitk::BaseRenderer::GetInstance(renderWindowPart->GetQmitkRenderWindow("sagittal")->renderWindow()); auto* coronalRenderer = mitk::BaseRenderer::GetInstance(renderWindowPart->GetQmitkRenderWindow("coronal")->renderWindow()); auto* threeDimRenderer = mitk::BaseRenderer::GetInstance(renderWindowPart->GetQmitkRenderWindow("3d")->renderWindow()); // set node properties if (m_DistanceImageNode.IsNotNull()) { this->m_DistanceImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_DistanceImageNode->SetVisibility( !useToF, sagittalRenderer ); this->m_DistanceImageNode->SetVisibility( !useToF, coronalRenderer ); this->m_DistanceImageNode->SetVisibility( !useToF, threeDimRenderer ); this->m_DistanceImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); } if (m_AmplitudeImageNode.IsNotNull()) { this->m_AmplitudeImageNode->SetVisibility( !useToF, axialRenderer ); this->m_AmplitudeImageNode->SetVisibility( !useToF, coronalRenderer ); this->m_AmplitudeImageNode->SetVisibility( !useToF, threeDimRenderer ); this->m_AmplitudeImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); } if (m_IntensityImageNode.IsNotNull()) { this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_IntensityImageNode->SetVisibility( !useToF, axialRenderer ); this->m_IntensityImageNode->SetVisibility( !useToF, sagittalRenderer ); this->m_IntensityImageNode->SetVisibility( !useToF, threeDimRenderer ); this->m_IntensityImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); } if ((m_RGBImageNode.IsNotNull())) { this->m_RGBImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_RGBImageNode->SetVisibility( !useToF, axialRenderer ); this->m_RGBImageNode->SetVisibility( !useToF, sagittalRenderer ); this->m_RGBImageNode->SetVisibility( !useToF, threeDimRenderer ); } // initialize images if (m_MitkDistanceImage.IsNotNull()) { - mitk::RenderingManager::GetInstance()->InitializeViews( - this->m_MitkDistanceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS, true); + mitk::RenderingManager::GetInstance()->InitializeViews( + this->m_MitkDistanceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); } if(this->m_SurfaceNode.IsNotNull()) { QHash renderWindowHashMap = renderWindowPart->GetQmitkRenderWindows(); QHashIterator i(renderWindowHashMap); while (i.hasNext()){ i.next(); this->m_SurfaceNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(i.value()->renderWindow()) ); } this->m_SurfaceNode->SetVisibility( true, mitk::BaseRenderer::GetInstance(renderWindowPart->GetQmitkRenderWindow("3d")->renderWindow() ) ); } //disable/enable gradient background renderWindowPart->EnableDecorations(!useToF, QStringList(QString("background"))); if((this->m_RGBImageNode.IsNotNull())) { bool RGBImageHasDifferentResolution = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("RGBImageHasDifferentResolution",RGBImageHasDifferentResolution); if(RGBImageHasDifferentResolution) { //update the display geometry by using the RBG image node. Only for renderwindow coronal - mitk::RenderingManager::GetInstance()->InitializeView( renderWindowPart->GetQmitkRenderWindow("coronal")->renderWindow(), this->m_RGBImageNode->GetData()->GetGeometry() ); + mitk::RenderingManager::GetInstance()->InitializeView(renderWindowPart->GetQmitkRenderWindow("coronal")->renderWindow(), + this->m_RGBImageNode->GetData()->GetGeometry()); } } } diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport.cpp b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport.cpp index 0931863ea5..187053fb21 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport.cpp +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport.cpp @@ -1,583 +1,581 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include //Mitk #include #include #include #include #include // Qmitk #include "QmitkUltrasoundSupport.h" // Qt #include #include #include // Ultrasound #include "mitkUSDevice.h" #include "QmitkUSAbstractCustomWidget.h" #include #include #include "usServiceReference.h" #include "internal/org_mitk_gui_qt_ultrasound_Activator.h" const std::string QmitkUltrasoundSupport::VIEW_ID = "org.mitk.views.ultrasoundsupport"; QmitkUltrasoundSupport::QmitkUltrasoundSupport() : m_Controls(nullptr), m_ControlCustomWidget(nullptr), m_ControlBModeWidget(nullptr), m_ControlProbesWidget(nullptr), m_ImageAlreadySetToNode(false), m_CurrentImageWidth(0), m_CurrentImageHeight(0) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { // to be notified about service event of an USDevice pluginContext->connectServiceListener(this, "OnDeviceServiceEvent", QString::fromStdString("(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")")); } } QmitkUltrasoundSupport::~QmitkUltrasoundSupport() { try { StoreUISettings(); StopTimers(); // Get all active devicesand deactivate them to prevent freeze std::vector devices = this->m_Controls->m_ActiveVideoDevices->GetAllServices(); for (size_t i = 0; i < devices.size(); i++) { mitk::USDevice::Pointer device = devices[i]; if (device.IsNotNull() && device->GetIsActive()) { device->Deactivate(); device->Disconnect(); } } } catch (std::exception &e) { MITK_ERROR << "Exception during call of destructor! Message: " << e.what(); } } void QmitkUltrasoundSupport::SetFocus() { } void QmitkUltrasoundSupport::CreateQtPartControl(QWidget *parent) { //initialize timers m_UpdateTimer = new QTimer(this); m_RenderingTimer2d = new QTimer(this); m_RenderingTimer3d = new QTimer(this); // build up qt view, unless already done if (!m_Controls) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::UltrasoundSupportControls; // create GUI widgets from the Qt Designer's .ui file m_Controls->setupUi(parent); //load persistence data before connecting slots (so no slots are called in this phase...) LoadUISettings(); //connect signals and slots... connect(m_Controls->m_DeviceManagerWidget, SIGNAL(NewDeviceButtonClicked()), this, SLOT(OnClickedAddNewDevice())); // Change Widget Visibilities connect(m_Controls->m_DeviceManagerWidget, SIGNAL(NewDeviceButtonClicked()), this->m_Controls->m_NewVideoDeviceWidget, SLOT(CreateNewDevice())); // Init NewDeviceWidget connect(m_Controls->m_ActiveVideoDevices, SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(OnChangedActiveDevice())); connect(m_Controls->m_RunImageTimer, SIGNAL(clicked()), this, SLOT(OnChangedActiveDevice())); connect(m_Controls->m_ShowImageStream, SIGNAL(clicked()), this, SLOT(OnChangedActiveDevice())); connect(m_Controls->m_NewVideoDeviceWidget, SIGNAL(Finished()), this, SLOT(OnNewDeviceWidgetDone())); // After NewDeviceWidget finished editing connect(m_Controls->m_FrameRatePipeline, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls->m_FrameRate2d, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls->m_FrameRate3d, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls->m_FreezeButton, SIGNAL(clicked()), this, SLOT(OnClickedFreezeButton())); connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(UpdateImage())); connect(m_RenderingTimer2d, SIGNAL(timeout()), this, SLOT(RenderImage2d())); connect(m_RenderingTimer3d, SIGNAL(timeout()), this, SLOT(RenderImage3d())); connect(m_Controls->m_Update2DView, SIGNAL(clicked()), this, SLOT(StartTimers())); connect(m_Controls->m_Update3DView, SIGNAL(clicked()), this, SLOT(StartTimers())); connect(m_Controls->m_DeviceManagerWidget, SIGNAL(EditDeviceButtonClicked(mitk::USDevice::Pointer)), this, SLOT(OnClickedEditDevice())); //Change Widget Visibilities connect(m_Controls->m_DeviceManagerWidget, SIGNAL(EditDeviceButtonClicked(mitk::USDevice::Pointer)), this->m_Controls->m_NewVideoDeviceWidget, SLOT(EditDevice(mitk::USDevice::Pointer))); connect(m_Controls->m_SetXPoint1, SIGNAL(clicked()), this, SLOT(SetXPoint1())); connect(m_Controls->m_SetXPoint2, SIGNAL(clicked()), this, SLOT(SetXPoint2())); connect(m_Controls->m_SetYPoint1, SIGNAL(clicked()), this, SLOT(SetYPoint1())); connect(m_Controls->m_SetYPoint2, SIGNAL(clicked()), this, SLOT(SetYPoint2())); connect(m_Controls->m_SaveSpacing, SIGNAL(clicked()), this, SLOT(WriteSpacingToDevice())); // Initializations m_Controls->m_NewVideoDeviceWidget->setVisible(false); std::string filter = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE + "=true))"; m_Controls->m_ActiveVideoDevices->Initialize( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, filter); m_Controls->m_ActiveVideoDevices->SetAutomaticallySelectFirstEntry(true); m_FrameCounterPipeline = 0; m_FrameCounter2d = 0; m_FrameCounter3d = 0; m_Controls->tabWidget->setTabEnabled(1, false); } } void QmitkUltrasoundSupport::OnClickedAddNewDevice() { m_Controls->m_NewVideoDeviceWidget->setVisible(true); m_Controls->m_DeviceManagerWidget->setVisible(false); m_Controls->m_Headline->setText("Add New Video Device:"); m_Controls->m_WidgetActiveDevices->setVisible(false); } void QmitkUltrasoundSupport::OnClickedEditDevice() { m_Controls->m_NewVideoDeviceWidget->setVisible(true); m_Controls->m_DeviceManagerWidget->setVisible(false); m_Controls->m_WidgetActiveDevices->setVisible(false); m_Controls->m_Headline->setText("Edit Video Device:"); } void QmitkUltrasoundSupport::UpdateImage() { //Update device m_Device->Modified(); m_Device->Update(); //Only update the view if the image is shown if (m_Controls->m_ShowImageStream->isChecked()) { //Update data nodes for (size_t i = 0; i < m_AmountOfOutputs; i++) { mitk::Image::Pointer curOutput = m_Device->GetOutput(i); if (curOutput->IsEmpty()) { m_Node.at(i)->SetName("No Data received yet ..."); //create a noise image for correct initialization of level window, etc. mitk::Image::Pointer randomImage = mitk::ImageGenerator::GenerateRandomImage(32, 32, 1, 1, 1, 1, 1, 255, 0); m_Node.at(i)->SetData(randomImage); curOutput->SetGeometry(randomImage->GetGeometry()); } else { std::stringstream nodeName; nodeName << "US Viewing Stream - Image " << i; m_Node.at(i)->SetName(nodeName.str()); m_Node.at(i)->SetData(curOutput); m_Node.at(i)->Modified(); } // if the geometry changed: reinitialize the ultrasound image if ((i==0) && (m_OldGeometry.IsNotNull()) && (curOutput->GetGeometry() != nullptr) && (!mitk::Equal(*(m_OldGeometry.GetPointer()), *(curOutput->GetGeometry()), 0.0001, false)) ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if ((renderWindow != nullptr) && (curOutput->GetTimeGeometry()->IsValid()) && (m_Controls->m_ShowImageStream->isChecked())) { - renderWindow->GetRenderingManager()->InitializeViews( - curOutput->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - renderWindow->GetRenderingManager()->RequestUpdateAll(); + renderWindow->GetRenderingManager()->InitializeViews(curOutput->GetGeometry()); } m_CurrentImageWidth = curOutput->GetDimension(0); m_CurrentImageHeight = curOutput->GetDimension(1); m_OldGeometry = dynamic_cast(curOutput->GetGeometry()); } } } //Update frame counter m_FrameCounterPipeline++; if (m_FrameCounterPipeline >0) { //compute framerate of pipeline update int nMilliseconds = m_Clock.restart(); int fps = 1000.0 / nMilliseconds; m_FPSPipeline = fps; m_FrameCounterPipeline = 0; //display lowest framerate in UI int lowestFPS = m_FPSPipeline; if (m_Controls->m_Update2DView->isChecked() && (m_FPS2d < lowestFPS)) { lowestFPS = m_FPS2d; } if (m_Controls->m_Update3DView->isChecked() && (m_FPS3d < lowestFPS)) { lowestFPS = m_FPS3d; } m_Controls->m_FramerateLabel->setText("Current Framerate: " + QString::number(lowestFPS) + " FPS"); } } void QmitkUltrasoundSupport::RenderImage2d() { if (!m_Controls->m_Update2DView->isChecked()) return; this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); m_FrameCounter2d++; if (m_FrameCounter2d >0) { //compute framerate of 2d render window update int nMilliseconds = m_Clock2d.restart(); int fps = 1000.0f / (nMilliseconds); m_FPS2d = fps; m_FrameCounter2d = 0; } } void QmitkUltrasoundSupport::RenderImage3d() { if (!m_Controls->m_Update3DView->isChecked()) return; this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); m_FrameCounter3d++; if (m_FrameCounter3d >0) { //compute framerate of 2d render window update int nMilliseconds = m_Clock3d.restart(); int fps = 1000.0f / (nMilliseconds); m_FPS3d = fps; m_FrameCounter3d = 0; } } void QmitkUltrasoundSupport::OnChangedFramerateLimit() { StopTimers(); int intervalPipeline = (1000 / m_Controls->m_FrameRatePipeline->value()); int interval2D = (1000 / m_Controls->m_FrameRate2d->value()); int interval3D = (1000 / m_Controls->m_FrameRate3d->value()); SetTimerIntervals(intervalPipeline, interval2D, interval3D); StartTimers(); } void QmitkUltrasoundSupport::OnClickedFreezeButton() { if (m_Device.IsNull()) { MITK_WARN("UltrasoundSupport") << "Freeze button clicked though no device is selected."; return; } if (m_Device->GetIsFreezed()) { m_Device->SetIsFreezed(false); m_Controls->m_FreezeButton->setText("Freeze"); } else { m_Device->SetIsFreezed(true); m_Controls->m_FreezeButton->setText("Start Viewing Again"); } } void QmitkUltrasoundSupport::OnChangedActiveDevice() { //clean up and stop timer StopTimers(); this->RemoveControlWidgets(); for (size_t j = 0; j < m_Node.size(); j++) { this->GetDataStorage()->Remove(m_Node.at(j)); m_Node.at(j)->ReleaseData(); } m_Node.clear(); //get current device, abort if it is invalid m_Device = m_Controls->m_ActiveVideoDevices->GetSelectedService(); if (m_Device.IsNull()) { m_Controls->tabWidget->setTabEnabled(1, false); return; } m_AmountOfOutputs = m_Device->GetNumberOfIndexedOutputs(); // clear data storage, create new nodes and add for (size_t i = 0; i < m_AmountOfOutputs; i++) { mitk::DataNode::Pointer currentNode = mitk::DataNode::New(); std::stringstream nodeName; nodeName << "US Viewing Stream - Image " << i; currentNode->SetName(nodeName.str()); //create a dummy image (gray values 0..255) for correct initialization of level window, etc. mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); currentNode->SetData(dummyImage); m_OldGeometry = dynamic_cast(dummyImage->GetGeometry()); m_Node.push_back(currentNode); //show node if the option is enabled if (m_Controls->m_ShowImageStream->isChecked()) { this->GetDataStorage()->Add(m_Node.at(i)); } } //create the widgets for this device and enable the widget tab this->CreateControlWidgets(); m_Controls->tabWidget->setTabEnabled(1, true); //start timer if (m_Controls->m_RunImageTimer->isChecked()) { int intervalPipeline = (1000 / m_Controls->m_FrameRatePipeline->value()); int interval2D = (1000 / m_Controls->m_FrameRate2d->value()); int interval3D = (1000 / m_Controls->m_FrameRate3d->value()); SetTimerIntervals(intervalPipeline, interval2D, interval3D); StartTimers(); m_Controls->m_TimerWidget->setEnabled(true); } else { m_Controls->m_TimerWidget->setEnabled(false); } } void QmitkUltrasoundSupport::OnNewDeviceWidgetDone() { m_Controls->m_NewVideoDeviceWidget->setVisible(false); m_Controls->m_DeviceManagerWidget->setVisible(true); m_Controls->m_Headline->setText("Ultrasound Devices:"); m_Controls->m_WidgetActiveDevices->setVisible(true); } void QmitkUltrasoundSupport::CreateControlWidgets() { m_ControlProbesWidget = new QmitkUSControlsProbesWidget(m_Device->GetControlInterfaceProbes(), m_Controls->m_ToolBoxControlWidgets); m_Controls->probesWidgetContainer->addWidget(m_ControlProbesWidget); // create b mode widget for current device m_ControlBModeWidget = new QmitkUSControlsBModeWidget(m_Device->GetControlInterfaceBMode(), m_Controls->m_ToolBoxControlWidgets); m_Controls->m_ToolBoxControlWidgets->addItem(m_ControlBModeWidget, "B Mode Controls"); if (!m_Device->GetControlInterfaceBMode()) { m_Controls->m_ToolBoxControlWidgets->setItemEnabled(m_Controls->m_ToolBoxControlWidgets->count() - 1, false); } // create doppler widget for current device m_ControlDopplerWidget = new QmitkUSControlsDopplerWidget(m_Device->GetControlInterfaceDoppler(), m_Controls->m_ToolBoxControlWidgets); m_Controls->m_ToolBoxControlWidgets->addItem(m_ControlDopplerWidget, "Doppler Controls"); if (!m_Device->GetControlInterfaceDoppler()) { m_Controls->m_ToolBoxControlWidgets->setItemEnabled(m_Controls->m_ToolBoxControlWidgets->count() - 1, false); } ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { std::string filter = "(org.mitk.services.UltrasoundCustomWidget.deviceClass=" + m_Device->GetDeviceClass() + ")"; //Hint: The following three lines are a workaround. Till now the only US video device was an USVideoDevice. // And everything worked fine. However, the ultrasound image source can be an USIGTLDevice (IGTL Client), as well. // This second option wasn't considered yet. So, the custom control widget will work correctly only, if // the filter declares the device class as org.mitk.modules.us.USVideoDevice. Another option, how to deal with // the two possible ultrasound image devices would be to change the returned string of the method // std::string QmitkUSControlsCustomVideoDeviceWidget::GetDeviceClass(), which always returns the string // org.mitk.modules.us.USVideoDevice of the USVideoDevice class. If there is a possility to change the // returned string dynamically between "IGTL Client" and "org.mitk.modules.us.USVideoDevice" the following // three lines will not be needed. if (m_Device->GetDeviceClass().compare("IGTL Client") == 0) { filter = "(org.mitk.services.UltrasoundCustomWidget.deviceClass=" + mitk::USVideoDevice::GetDeviceClassStatic() + ")"; } QString interfaceName = QString::fromStdString(us_service_interface_iid()); m_CustomWidgetServiceReference = pluginContext->getServiceReferences(interfaceName, QString::fromStdString(filter)); if (m_CustomWidgetServiceReference.size() > 0) { m_ControlCustomWidget = pluginContext->getService (m_CustomWidgetServiceReference.at(0))->CloneForQt(m_Controls->tab2); m_ControlCustomWidget->SetDevice(m_Device); m_Controls->m_ToolBoxControlWidgets->addItem(m_ControlCustomWidget, "Custom Controls"); } else { m_Controls->m_ToolBoxControlWidgets->addItem(new QWidget(m_Controls->m_ToolBoxControlWidgets), "Custom Controls"); m_Controls->m_ToolBoxControlWidgets->setItemEnabled(m_Controls->m_ToolBoxControlWidgets->count() - 1, false); } } // select first enabled control widget for (int n = 0; n < m_Controls->m_ToolBoxControlWidgets->count(); ++n) { if (m_Controls->m_ToolBoxControlWidgets->isItemEnabled(n)) { m_Controls->m_ToolBoxControlWidgets->setCurrentIndex(n); break; } } } void QmitkUltrasoundSupport::RemoveControlWidgets() { if (!m_ControlProbesWidget) { return; } //widgets do not exist... nothing to do // remove all control widgets from the tool box widget while (m_Controls->m_ToolBoxControlWidgets->count() > 0) { m_Controls->m_ToolBoxControlWidgets->removeItem(0); } // remove probes widget (which is not part of the tool box widget) m_Controls->probesWidgetContainer->removeWidget(m_ControlProbesWidget); delete m_ControlProbesWidget; m_ControlProbesWidget = nullptr; delete m_ControlBModeWidget; m_ControlBModeWidget = nullptr; delete m_ControlDopplerWidget; m_ControlDopplerWidget = nullptr; // delete custom widget if it is present if (m_ControlCustomWidget) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); delete m_ControlCustomWidget; m_ControlCustomWidget = nullptr; if (m_CustomWidgetServiceReference.size() > 0) { pluginContext->ungetService(m_CustomWidgetServiceReference.at(0)); } } } void QmitkUltrasoundSupport::OnDeviceServiceEvent(const ctkServiceEvent event) { if (m_Device.IsNull() || event.getType() != ctkServiceEvent::MODIFIED) { return; } ctkServiceReference service = event.getServiceReference(); if (m_Device->GetManufacturer() != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER)).toString().toStdString() && m_Device->GetName() != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME)).toString().toStdString()) { return; } if (!m_Device->GetIsActive() && m_UpdateTimer->isActive()) { StopTimers(); } if (m_CurrentDynamicRange != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DYNAMIC_RANGE)).toDouble()) { m_CurrentDynamicRange = service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DYNAMIC_RANGE)).toDouble(); // update level window for the current dynamic range mitk::LevelWindow levelWindow; m_Node.at(0)->GetLevelWindow(levelWindow); levelWindow.SetAuto(m_curOutput.at(0), true, true); m_Node.at(0)->SetLevelWindow(levelWindow); } } void QmitkUltrasoundSupport::StoreUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); settings.setValue("DisplayImage", QVariant(m_Controls->m_ShowImageStream->isChecked())); settings.setValue("RunImageTimer", QVariant(m_Controls->m_RunImageTimer->isChecked())); settings.setValue("Update2DView", QVariant(m_Controls->m_Update2DView->isChecked())); settings.setValue("Update3DView", QVariant(m_Controls->m_Update3DView->isChecked())); settings.setValue("UpdateRatePipeline", QVariant(m_Controls->m_FrameRatePipeline->value())); settings.setValue("UpdateRate2d", QVariant(m_Controls->m_FrameRate2d->value())); settings.setValue("UpdateRate3d", QVariant(m_Controls->m_FrameRate3d->value())); settings.endGroup(); } void QmitkUltrasoundSupport::LoadUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); m_Controls->m_ShowImageStream->setChecked(settings.value("DisplayImage", true).toBool()); m_Controls->m_RunImageTimer->setChecked(settings.value("RunImageTimer", true).toBool()); m_Controls->m_Update2DView->setChecked(settings.value("Update2DView", true).toBool()); m_Controls->m_Update3DView->setChecked(settings.value("Update3DView", true).toBool()); m_Controls->m_FrameRatePipeline->setValue(settings.value("UpdateRatePipeline", 50).toInt()); m_Controls->m_FrameRate2d->setValue(settings.value("UpdateRate2d", 20).toInt()); m_Controls->m_FrameRate3d->setValue(settings.value("UpdateRate3d", 5).toInt()); settings.endGroup(); } void QmitkUltrasoundSupport::StartTimers() { m_Clock.start(); m_UpdateTimer->start(); if (m_Controls->m_Update2DView->isChecked()) { m_RenderingTimer2d->start(); } if (m_Controls->m_Update3DView->isChecked()) { m_RenderingTimer3d->start(); } } void QmitkUltrasoundSupport::StopTimers() { m_UpdateTimer->stop(); m_RenderingTimer2d->stop(); m_RenderingTimer3d->stop(); } void QmitkUltrasoundSupport::SetTimerIntervals(int intervalPipeline, int interval2D, int interval3D) { m_UpdateTimer->setInterval(intervalPipeline); m_RenderingTimer2d->setInterval(interval2D); m_RenderingTimer3d->setInterval(interval3D); } /* Spacing methods */ void QmitkUltrasoundSupport::SetXPoint1() { m_Xpoint1 = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetSelectedPosition(); m_XSpacing = ComputeSpacing(m_Xpoint1, m_Xpoint2, m_Controls->m_XDistance->value()); m_Controls->m_XSpacing->setText(QString("X Spacing: ") + QString::number(m_XSpacing) + " mm"); } void QmitkUltrasoundSupport::SetXPoint2() { m_Xpoint2 = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetSelectedPosition(); m_XSpacing = ComputeSpacing(m_Xpoint1, m_Xpoint2, m_Controls->m_XDistance->value()); m_Controls->m_XSpacing->setText(QString("X Spacing: ") + QString::number(m_XSpacing) + " mm"); } void QmitkUltrasoundSupport::SetYPoint1() { m_Ypoint1 = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetSelectedPosition(); m_YSpacing = ComputeSpacing(m_Ypoint1, m_Ypoint2, m_Controls->m_YDistance->value()); m_Controls->m_YSpacing->setText(QString("Y Spacing: ") + QString::number(m_YSpacing) + " mm"); } void QmitkUltrasoundSupport::SetYPoint2() { m_Ypoint2 = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetSelectedPosition(); m_YSpacing = ComputeSpacing(m_Ypoint1, m_Ypoint2, m_Controls->m_YDistance->value()); m_Controls->m_YSpacing->setText(QString("Y Spacing: ") + QString::number(m_YSpacing) + " mm"); } void QmitkUltrasoundSupport::WriteSpacingToDevice() { this->m_Device->SetSpacing(m_XSpacing, m_YSpacing); MITK_INFO << "Spacing saved to device object, please save device data to permanently store the spacing."; } double QmitkUltrasoundSupport::ComputeSpacing(mitk::Point3D p1, mitk::Point3D p2, double distance) { double spacing = 0; double pointDistance = p1.EuclideanDistanceTo(p2); spacing = distance / pointDistance; return spacing; } diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport_old.cpp b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport_old.cpp index e153326b42..f44e8b0d7b 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport_old.cpp +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport_old.cpp @@ -1,608 +1,606 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include #include //Mitk #include #include #include #include #include #include #include #include "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include #include // Qmitk #include "QmitkUltrasoundSupport.h" // Qt #include #include #include // Ultrasound #include "mitkUSDevice.h" #include "QmitkUSAbstractCustomWidget.h" #include #include #include "usServiceReference.h" #include "internal/org_mitk_gui_qt_ultrasound_Activator.h" #include "mitkNodePredicateDataType.h" #include const std::string QmitkUltrasoundSupport::VIEW_ID = "org.mitk.views.ultrasoundsupport"; void QmitkUltrasoundSupport::SetFocus() { } void QmitkUltrasoundSupport::CreateQtPartControl(QWidget *parent) { //initialize timers m_UpdateTimer = new QTimer(this); m_RenderingTimer2d = new QTimer(this); m_RenderingTimer3d = new QTimer(this); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); //load persistence data before connecting slots (so no slots are called in this phase...) LoadUISettings(); //connect signals and slots... connect(m_Controls.m_DeviceManagerWidget, SIGNAL(NewDeviceButtonClicked()), this, SLOT(OnClickedAddNewDevice())); // Change Widget Visibilities connect(m_Controls.m_DeviceManagerWidget, SIGNAL(NewDeviceButtonClicked()), this->m_Controls.m_NewVideoDeviceWidget, SLOT(CreateNewDevice())); // Init NewDeviceWidget connect(m_Controls.m_ActiveVideoDevices, SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(OnChangedActiveDevice())); connect(m_Controls.m_RunImageTimer, SIGNAL(clicked()), this, SLOT(OnChangedActiveDevice())); connect(m_Controls.m_ShowImageStream, SIGNAL(clicked()), this, SLOT(OnChangedActiveDevice())); connect(m_Controls.m_NewVideoDeviceWidget, SIGNAL(Finished()), this, SLOT(OnNewDeviceWidgetDone())); // After NewDeviceWidget finished editing connect(m_Controls.m_FrameRatePipeline, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls.m_FrameRate2d, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls.m_FrameRate3d, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls.m_FreezeButton, SIGNAL(clicked()), this, SLOT(OnClickedFreezeButton())); connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(UpdateImage())); connect(m_RenderingTimer2d, SIGNAL(timeout()), this, SLOT(RenderImage2d())); connect(m_RenderingTimer3d, SIGNAL(timeout()), this, SLOT(RenderImage3d())); connect(m_Controls.m_Update2DView, SIGNAL(clicked()), this, SLOT(StartTimers())); connect(m_Controls.m_Update3DView, SIGNAL(clicked()), this, SLOT(StartTimers())); connect(m_Controls.m_DeviceManagerWidget, SIGNAL(EditDeviceButtonClicked(mitk::USDevice::Pointer)), this, SLOT(OnClickedEditDevice())); //Change Widget Visibilities connect(m_Controls.m_DeviceManagerWidget, SIGNAL(EditDeviceButtonClicked(mitk::USDevice::Pointer)), this->m_Controls.m_NewVideoDeviceWidget, SLOT(EditDevice(mitk::USDevice::Pointer))); // Initializations m_Controls.m_NewVideoDeviceWidget->setVisible(false); std::string filter = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE + "=true))"; m_Controls.m_ActiveVideoDevices->Initialize( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, filter); m_Controls.m_ActiveVideoDevices->SetAutomaticallySelectFirstEntry(true); m_FrameCounterPipeline = 0; m_FrameCounter2d = 0; m_FrameCounter3d = 0; m_Controls.tabWidget->setTabEnabled(1, false); } void QmitkUltrasoundSupport::InitNewNode() { m_Node.push_back(nullptr); auto& Node = m_Node.back(); Node = mitk::DataNode::New(); char name[30]; sprintf(name, "US Viewing Stream - Image %d", (unsigned int)(m_Node.size() - 1)); Node->SetName(name); //create a dummy image (gray values 0..255) for correct initialization of level window, etc. mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); Node->SetData(dummyImage); m_OldGeometry = dynamic_cast(dummyImage->GetGeometry()); this->GetDataStorage()->Add(Node); } void QmitkUltrasoundSupport::DestroyLastNode() { auto& Node = m_Node.back(); this->GetDataStorage()->Remove(Node); // clean up Node->ReleaseData(); m_Node.pop_back(); } void QmitkUltrasoundSupport::UpdateLevelWindows() { mitk::LevelWindow levelWindow; if (m_Node.size() > 0) { for (unsigned int index = 0; index < m_AmountOfOutputs; ++index) { m_Node[index]->GetLevelWindow(levelWindow); if (!m_curOutput[index]->IsEmpty()) levelWindow.SetToImageRange(m_curOutput[index]); m_Node[index]->SetLevelWindow(levelWindow); } } } void QmitkUltrasoundSupport::SetColormap(mitk::DataNode::Pointer node, mitk::LookupTable::LookupTableType type) { mitk::LookupTable::Pointer lookupTable = mitk::LookupTable::New(); mitk::LookupTableProperty::Pointer lookupTableProperty = mitk::LookupTableProperty::New(); lookupTable->SetType(type); lookupTableProperty->SetLookupTable(lookupTable); node->SetProperty("LookupTable", lookupTableProperty); mitk::RenderingModeProperty::Pointer renderingMode = dynamic_cast(node->GetProperty("Image Rendering.Mode")); renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); } void QmitkUltrasoundSupport::OnClickedAddNewDevice() { m_Controls.m_NewVideoDeviceWidget->setVisible(true); m_Controls.m_DeviceManagerWidget->setVisible(false); m_Controls.m_Headline->setText("Add New Video Device:"); m_Controls.m_WidgetActiveDevices->setVisible(false); } void QmitkUltrasoundSupport::OnClickedEditDevice() { m_Controls.m_NewVideoDeviceWidget->setVisible(true); m_Controls.m_DeviceManagerWidget->setVisible(false); m_Controls.m_WidgetActiveDevices->setVisible(false); m_Controls.m_Headline->setText("Edit Video Device:"); } void QmitkUltrasoundSupport::UpdateAmountOfOutputs() { // correct the amount of Nodes to display data while (m_Node.size() < m_AmountOfOutputs) { InitNewNode(); } while (m_Node.size() > m_AmountOfOutputs) { DestroyLastNode(); } // correct the amount of image outputs that we feed the nodes with while (m_curOutput.size() < m_AmountOfOutputs) { m_curOutput.push_back(mitk::Image::New()); unsigned int dim[3] = { 2, 2, 1}; m_curOutput.back()->Initialize(mitk::MakeScalarPixelType(), 3, dim); } while (m_curOutput.size() > m_AmountOfOutputs) { m_curOutput.pop_back(); } } void QmitkUltrasoundSupport::UpdateImage() { if (m_Controls.m_ShowImageStream->isChecked()) { m_Device->Modified(); m_Device->Update(); // Update device if (m_AmountOfOutputs == 0) return; // if there is no image to be displayed, skip the rest of this method for (unsigned int index = 0; index < m_AmountOfOutputs; ++index) { auto image = m_Device->GetOutput(index); // get the Image data to display if (!image->IsEmpty()) { if (m_curOutput[index]->GetDimension(0) != image->GetDimension(0) || m_curOutput[index]->GetDimension(1) != image->GetDimension(1) || m_curOutput[index]->GetDimension(2) != image->GetDimension(2) || m_curOutput[index]->GetPixelType() != image->GetPixelType()) { m_curOutput[index]->Initialize(image->GetPixelType(), image->GetDimension(), image->GetDimensions()); // if we switched image resolution or type the outputs must be reinitialized! } // copy the contents of the device output into the image the data storage will display mitk::ImageReadAccessor inputReadAccessor(image); m_curOutput[index]->SetImportVolume(inputReadAccessor.GetData()); m_curOutput[index]->GetGeometry()->SetIndexToWorldTransform(image->GetSlicedGeometry()->GetIndexToWorldTransform()); } if (m_curOutput[index]->IsEmpty()) { // create a noise image for correct initialization of level window, etc. mitk::Image::Pointer randomImage = mitk::ImageGenerator::GenerateRandomImage(32, 32, 1, 1, 1, 1, 1, 255, 0); m_Node[index]->SetData(randomImage); m_curOutput[index]->SetGeometry(randomImage->GetGeometry()); } else { m_Node[index]->SetData(m_curOutput[index]); } } float eps = 0.000001f; // if the geometry changed: reinitialize the ultrasound image. we use the m_curOutput[0] to readjust the geometry if (((m_OldGeometry.IsNotNull()) && (m_curOutput[0]->GetGeometry() != nullptr)) && ( (abs(m_OldGeometry->GetSpacing()[0] - m_curOutput[0]->GetGeometry()->GetSpacing()[0]) > eps) || (abs(m_OldGeometry->GetSpacing()[1] - m_curOutput[0]->GetGeometry()->GetSpacing()[1]) > eps) || (abs(m_OldGeometry->GetCenter()[0] - m_curOutput[0]->GetGeometry()->GetCenter()[0]) > eps) || (abs(m_OldGeometry->GetCenter()[1] - m_curOutput[0]->GetGeometry()->GetCenter()[1]) > eps) || m_ForceRequestUpdateAll)) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if ((renderWindow != nullptr) && (m_curOutput[0]->GetTimeGeometry()->IsValid()) && (m_Controls.m_ShowImageStream->isChecked())) { - renderWindow->GetRenderingManager()->InitializeViews( - m_curOutput[0]->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - renderWindow->GetRenderingManager()->RequestUpdateAll(); + renderWindow->GetRenderingManager()->InitializeViews(m_curOutput[0]->GetGeometry()); } m_CurrentImageWidth = m_curOutput[0]->GetDimension(0); m_CurrentImageHeight = m_curOutput[0]->GetDimension(1); m_OldGeometry = dynamic_cast(m_curOutput[0]->GetGeometry()); UpdateLevelWindows(); m_ForceRequestUpdateAll = false; } } //Update frame counter m_FrameCounterPipeline++; if (m_FrameCounterPipeline >= 10) { // compute framerate of pipeline update int nMilliseconds = m_Clock.restart(); int fps = 10000.0f / (nMilliseconds); m_FPSPipeline = fps; m_FrameCounterPipeline = 0; // display lowest framerate in UI int lowestFPS = m_FPSPipeline; if (m_Controls.m_Update2DView->isChecked() && (m_FPS2d < lowestFPS)) { lowestFPS = m_FPS2d; } if (m_Controls.m_Update3DView->isChecked() && (m_FPS3d < lowestFPS)) { lowestFPS = m_FPS3d; } m_Controls.m_FramerateLabel->setText("Current Framerate: " + QString::number(lowestFPS) + " FPS"); } } void QmitkUltrasoundSupport::RenderImage2d() { if (!m_Controls.m_Update2DView->isChecked()) return; //mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); //renderWindow->GetRenderingManager()->RequestUpdate(mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget0"))->GetRenderWindow()); this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); m_FrameCounter2d++; if (m_FrameCounter2d >= 10) { // compute framerate of 2d render window update int nMilliseconds = m_Clock2d.restart(); int fps = 10000.0f / (nMilliseconds); m_FPS2d = fps; m_FrameCounter2d = 0; } } void QmitkUltrasoundSupport::RenderImage3d() { if (!m_Controls.m_Update3DView->isChecked()) return; this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); m_FrameCounter3d++; if (m_FrameCounter3d >= 10) { // compute framerate of 2d render window update int nMilliseconds = m_Clock3d.restart(); int fps = 10000.0f / (nMilliseconds); m_FPS3d = fps; m_FrameCounter3d = 0; } } void QmitkUltrasoundSupport::OnChangedFramerateLimit() { StopTimers(); int intervalPipeline = (1000 / m_Controls.m_FrameRatePipeline->value()); int interval2D = (1000 / m_Controls.m_FrameRate2d->value()); int interval3D = (1000 / m_Controls.m_FrameRate3d->value()); SetTimerIntervals(intervalPipeline, interval2D, interval3D); StartTimers(); } void QmitkUltrasoundSupport::OnClickedFreezeButton() { if (m_Device.IsNull()) { MITK_WARN("UltrasoundSupport") << "Freeze button clicked though no device is selected."; return; } if (m_Device->GetIsFreezed()) { m_Device->SetIsFreezed(false); m_Controls.m_FreezeButton->setText("Freeze"); } else { m_Device->SetIsFreezed(true); m_Controls.m_FreezeButton->setText("Start Viewing Again"); } } void QmitkUltrasoundSupport::OnChangedActiveDevice() { //clean up, delete nodes and stop timer StopTimers(); this->RemoveControlWidgets(); for (auto& Node : m_Node) { this->GetDataStorage()->Remove(Node); Node->ReleaseData(); } m_Node.clear(); //get current device, abort if it is invalid m_Device = m_Controls.m_ActiveVideoDevices->GetSelectedService(); if (m_Device.IsNull()) { m_Controls.tabWidget->setTabEnabled(1, false); return; } //create the widgets for this device and enable the widget tab this->CreateControlWidgets(); m_Controls.tabWidget->setTabEnabled(1, true); //start timer if (m_Controls.m_RunImageTimer->isChecked()) { int intervalPipeline = (1000 / m_Controls.m_FrameRatePipeline->value()); int interval2D = (1000 / m_Controls.m_FrameRate2d->value()); int interval3D = (1000 / m_Controls.m_FrameRate3d->value()); SetTimerIntervals(intervalPipeline, interval2D, interval3D); StartTimers(); m_Controls.m_TimerWidget->setEnabled(true); } else { m_Controls.m_TimerWidget->setEnabled(false); } m_AmountOfOutputs = m_Device->GetNumberOfIndexedOutputs(); // create as many nodes and image outputs as needed UpdateAmountOfOutputs(); } void QmitkUltrasoundSupport::OnNewDeviceWidgetDone() { m_Controls.m_NewVideoDeviceWidget->setVisible(false); m_Controls.m_DeviceManagerWidget->setVisible(true); m_Controls.m_Headline->setText("Ultrasound Devices:"); m_Controls.m_WidgetActiveDevices->setVisible(true); } void QmitkUltrasoundSupport::CreateControlWidgets() { m_ControlProbesWidget = new QmitkUSControlsProbesWidget(m_Device->GetControlInterfaceProbes(), m_Controls.m_ToolBoxControlWidgets); m_Controls.probesWidgetContainer->addWidget(m_ControlProbesWidget); // create b mode widget for current device m_ControlBModeWidget = new QmitkUSControlsBModeWidget(m_Device->GetControlInterfaceBMode(), m_Controls.m_ToolBoxControlWidgets); if (m_Device->GetControlInterfaceBMode()) { m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlBModeWidget, "B Mode Controls"); //m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); } // create doppler widget for current device m_ControlDopplerWidget = new QmitkUSControlsDopplerWidget(m_Device->GetControlInterfaceDoppler(), m_Controls.m_ToolBoxControlWidgets); if (m_Device->GetControlInterfaceDoppler()) { m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlDopplerWidget, "Doppler Controls"); //m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); } ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { std::string filter = "(org.mitk.services.UltrasoundCustomWidget.deviceClass=" + m_Device->GetDeviceClass() + ")"; QString interfaceName = QString::fromStdString(us_service_interface_iid()); m_CustomWidgetServiceReference = pluginContext->getServiceReferences(interfaceName, QString::fromStdString(filter)); if (m_CustomWidgetServiceReference.size() > 0) { m_ControlCustomWidget = pluginContext->getService (m_CustomWidgetServiceReference.at(0))->CloneForQt(m_Controls.tab2); m_ControlCustomWidget->SetDevice(m_Device); m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlCustomWidget, "Custom Controls"); } else { m_Controls.m_ToolBoxControlWidgets->addItem(new QWidget(m_Controls.m_ToolBoxControlWidgets), "Custom Controls"); m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); } } // select first enabled control widget for (int n = 0; n < m_Controls.m_ToolBoxControlWidgets->count(); ++n) { if (m_Controls.m_ToolBoxControlWidgets->isItemEnabled(n)) { m_Controls.m_ToolBoxControlWidgets->setCurrentIndex(n); break; } } } void QmitkUltrasoundSupport::RemoveControlWidgets() { if (!m_ControlProbesWidget) { return; } //widgets do not exist... nothing to do // remove all control widgets from the tool box widget while (m_Controls.m_ToolBoxControlWidgets->count() > 0) { m_Controls.m_ToolBoxControlWidgets->removeItem(0); } // remove probes widget (which is not part of the tool box widget) m_Controls.probesWidgetContainer->removeWidget(m_ControlProbesWidget); delete m_ControlProbesWidget; m_ControlProbesWidget = 0; delete m_ControlBModeWidget; m_ControlBModeWidget = 0; delete m_ControlDopplerWidget; m_ControlDopplerWidget = 0; // delete custom widget if it is present if (m_ControlCustomWidget) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); delete m_ControlCustomWidget; m_ControlCustomWidget = 0; if (m_CustomWidgetServiceReference.size() > 0) { pluginContext->ungetService(m_CustomWidgetServiceReference.at(0)); } } } void QmitkUltrasoundSupport::OnDeviceServiceEvent(const ctkServiceEvent event) { if (m_Device.IsNull() || event.getType() != static_cast(us::ServiceEvent::MODIFIED)) { return; } ctkServiceReference service = event.getServiceReference(); if (m_Device->GetManufacturer() != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER)).toString().toStdString() && m_Device->GetName() != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME)).toString().toStdString()) { return; } if (!m_Device->GetIsActive() && m_UpdateTimer->isActive()) { StopTimers(); } if (m_CurrentDynamicRange != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DYNAMIC_RANGE)).toDouble()) { m_CurrentDynamicRange = service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DYNAMIC_RANGE)).toDouble(); UpdateLevelWindows(); } } QmitkUltrasoundSupport::QmitkUltrasoundSupport() : m_ControlCustomWidget(0), m_ControlBModeWidget(0), m_ControlProbesWidget(0), m_ImageAlreadySetToNode(false), m_CurrentImageWidth(0), m_CurrentImageHeight(0), m_AmountOfOutputs(0), m_ForceRequestUpdateAll(false) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { // to be notified about service event of an USDevice pluginContext->connectServiceListener(this, "OnDeviceServiceEvent", QString::fromStdString("(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")")); } } QmitkUltrasoundSupport::~QmitkUltrasoundSupport() { try { StoreUISettings(); StopTimers(); // Get all active devicesand deactivate them to prevent freeze for (auto device : this->m_Controls.m_ActiveVideoDevices->GetAllServices()) { if (device != nullptr && device->GetIsActive()) { device->Deactivate(); device->Disconnect(); } } } catch (std::exception &e) { MITK_ERROR << "Exception during call of destructor! Message: " << e.what(); } } void QmitkUltrasoundSupport::StoreUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); settings.setValue("DisplayImage", QVariant(m_Controls.m_ShowImageStream->isChecked())); settings.setValue("RunImageTimer", QVariant(m_Controls.m_RunImageTimer->isChecked())); settings.setValue("Update2DView", QVariant(m_Controls.m_Update2DView->isChecked())); settings.setValue("Update3DView", QVariant(m_Controls.m_Update3DView->isChecked())); settings.setValue("UpdateRatePipeline", QVariant(m_Controls.m_FrameRatePipeline->value())); settings.setValue("UpdateRate2d", QVariant(m_Controls.m_FrameRate2d->value())); settings.setValue("UpdateRate3d", QVariant(m_Controls.m_FrameRate3d->value())); settings.endGroup(); } void QmitkUltrasoundSupport::LoadUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); m_Controls.m_ShowImageStream->setChecked(settings.value("DisplayImage", true).toBool()); m_Controls.m_RunImageTimer->setChecked(settings.value("RunImageTimer", true).toBool()); m_Controls.m_Update2DView->setChecked(settings.value("Update2DView", true).toBool()); m_Controls.m_Update3DView->setChecked(settings.value("Update3DView", true).toBool()); m_Controls.m_FrameRatePipeline->setValue(settings.value("UpdateRatePipeline", 50).toInt()); m_Controls.m_FrameRate2d->setValue(settings.value("UpdateRate2d", 20).toInt()); m_Controls.m_FrameRate3d->setValue(settings.value("UpdateRate3d", 5).toInt()); settings.endGroup(); } void QmitkUltrasoundSupport::StartTimers() { m_UpdateTimer->start(); if (m_Controls.m_Update2DView->isChecked()) { m_RenderingTimer2d->start(); } if (m_Controls.m_Update3DView->isChecked()) { m_RenderingTimer3d->start(); } } void QmitkUltrasoundSupport::StopTimers() { m_UpdateTimer->stop(); m_RenderingTimer2d->stop(); m_RenderingTimer3d->stop(); } void QmitkUltrasoundSupport::SetTimerIntervals(int intervalPipeline, int interval2D, int interval3D) { m_UpdateTimer->setInterval(intervalPipeline); m_RenderingTimer2d->setInterval(interval2D); m_RenderingTimer3d->setInterval(interval3D); }