diff --git a/BlueBerry/CMakeLists.txt b/BlueBerry/CMakeLists.txt index ab3b06adad..4be3b99ef6 100644 --- a/BlueBerry/CMakeLists.txt +++ b/BlueBerry/CMakeLists.txt @@ -1,272 +1,276 @@ project(BlueBerry) cmake_minimum_required(VERSION 2.8.4) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMake/") include(MacroParseArguments) include(MacroConvertSchema) include(MacroOrganizeSources) include(MacroCreateCTKPlugin) include(MacroCreateQtHelp) include(MacroInstallCTKPlugin) include(FunctionCreateProvisioningFile) if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4250 /wd4275 /wd4251 /wd4503") endif() if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) endif() find_package(mbilog REQUIRED) include_directories(${mbilog_INCLUDE_DIRS}) find_package(Qt4 4.6.2 REQUIRED) if(QT_QMAKE_CHANGED) set(QT_HELPGENERATOR_EXECUTABLE NOTFOUND) set(QT_COLLECTIONGENERATOR_EXECUTABLE NOTFOUND) set(QT_ASSISTANT_EXECUTABLE NOTFOUND) set(QT_XMLPATTERNS_EXECUTABLE NOTFOUND) endif() find_program(QT_HELPGENERATOR_EXECUTABLE NAMES qhelpgenerator qhelpgenerator-qt4 qhelpgenerator4 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_COLLECTIONGENERATOR_EXECUTABLE NAMES qcollectiongenerator qcollectiongenerator-qt4 qcollectiongenerator4 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_ASSISTANT_EXECUTABLE NAMES assistant-qt4 assistant4 assistant PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_XMLPATTERNS_EXECUTABLE NAMES xmlpatterns PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) option(BLUEBERRY_USE_QT_HELP "Enable support for integrating bundle documentation into Qt Help" ON) mark_as_advanced(BLUEBERRY_USE_QT_HELP QT_HELPGENERATOR_EXECUTABLE QT_COLLECTIONGENERATOR_EXECUTABLE QT_ASSISTANT_EXECUTABLE QT_XMLPATTERNS_EXECUTABLE) set(_doxygen_too_old 1) if(BLUEBERRY_USE_QT_HELP) find_package(Doxygen) if(DOXYGEN_FOUND) execute_process(COMMAND ${DOXYGEN_EXECUTABLE} --version OUTPUT_VARIABLE _doxygen_version) if(${_doxygen_version} VERSION_GREATER 1.6.0 OR ${_doxygen_version} VERSION_EQUAL 1.6.0) set(_doxygen_too_old 0) endif() endif() if(_doxygen_too_old) message("Doxygen was not found or is too old. Version 1.6.0 or later is needed if BLUEBERRY_USE_QT_HELP is ON") set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) endif() if(NOT QT_HELPGENERATOR_EXECUTABLE) message("You have enabled Qt Help support, but QT_HELPGENERATOR_EXECUTABLE is empty") set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) endif() if(NOT QT_XMLPATTERNS_EXECUTABLE) message("You have enabled Qt Help support, but QT_XMLPATTERNS_EXECUTABLE is empty") set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) endif() endif(BLUEBERRY_USE_QT_HELP) include(${QT_USE_FILE}) # ========= CTK specific CMake stuff ============ cmake_policy(SET CMP0012 NEW) find_package(CTK REQUIRED) # Extract all library names starting with org_blueberry_ macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin "^org_blueberry_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin OUTPUT_VARIABLE ${varname}) endmacro() # ================================================ option(BLUEBERRY_BUILD_ALL_PLUGINS "Build all BlueBerry plugins (overriding selection)" OFF) mark_as_advanced(BLUEBERRY_BUILD_ALL_PLUGINS) if(BLUEBERRY_BUILD_ALL_PLUGINS) set(BLUEBERRY_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() option(BLUEBERRY_STATIC "Build all plugins as static libraries" OFF) mark_as_advanced(BLUEBERRY_STATIC) option(BLUEBERRY_DEBUG_SMARTPOINTER "Enable code for debugging smart pointers" OFF) mark_as_advanced(BLUEBERRY_DEBUG_SMARTPOINTER) find_package(Poco REQUIRED) find_package(Ant) find_package(Eclipse) set(BLUEBERRY_SOURCE_DIR ${BlueBerry_SOURCE_DIR}) set(BLUEBERRY_BINARY_DIR ${BlueBerry_BINARY_DIR}) set(BLUEBERRY_PLUGINS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Bundles) set(BLUEBERRY_PLUGINS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Bundles) set(OSGI_APP solstice) set(OSGI_UI_APP solstice_ui) if(Eclipse_DIR) set(BLUEBERRY_DOC_TOOLS_DIR "${Eclipse_DIR}" CACHE PATH "Directory containing additional tools needed for generating the documentation") else() set(BLUEBERRY_DOC_TOOLS_DIR "" CACHE PATH "Directory containing additional tools needed for generating the documentation") endif() set(BLUEBERRY_DEBUG_POSTFIX d) # Testing options -option(BLUEBERRY_BUILD_TESTING "Build the BlueBerry tests." ${BUILD_TESTING}) +if(DEFINED BLUEBERRY_BUILD_TESTING) + option(BLUEBERRY_BUILD_TESTING "Build the BlueBerry tests." ${BLUEBERRY_BUILD_TESTING}) +else() + option(BLUEBERRY_BUILD_TESTING "Build the BlueBerry tests." ${BUILD_TESTING}) +endif() if(WIN32) set(_gui_testing_default "ON") else() set(_gui_testing_default "OFF") endif() option(BLUEBERRY_ENABLE_GUI_TESTING "Enable the BlueBerry GUI tests" ${_gui_testing_default}) mark_as_advanced(BLUEBERRY_ENABLE_GUI_TESTING) if(BLUEBERRY_BUILD_TESTING) enable_testing() endif() # Add CTK plugins set(_ctk_plugins Bundles/org.blueberry.osgi:ON Bundles/org.blueberry.compat:OFF Bundles/org.blueberry.core.runtime:OFF Bundles/org.blueberry.core.expressions:OFF Bundles/org.blueberry.solstice.common:OFF Bundles/org.blueberry.core.commands:OFF Bundles/org.blueberry.core.jobs:OFF Bundles/org.blueberry.ui:OFF Bundles/org.blueberry.ui.qt:OFF Bundles/org.blueberry.ui.qt.help:OFF Bundles/org.blueberry.ui.qt.log:OFF Bundles/org.blueberry.ui.qt.objectinspector:OFF ) set(_ctk_test_plugins ) set(_ctk_plugins_include_dirs ${Poco_INCLUDE_DIRS} ) set(_ctk_plugins_link_dirs ${Poco_LIBRARY_DIR} ) include_directories(${_ctk_plugins_include_dirs}) link_directories(${_ctk_plugins_link_dirs}) if(BLUEBERRY_BUILD_TESTING) include(berryTestingHelpers) set(BLUEBERRY_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_APP}") get_target_property(_is_macosx_bundle ${OSGI_APP} MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_APP}.app/Contents/MacOS/${OSGI_APP}") endif() set(_ctk_testinfrastructure_plugins Bundles/org.blueberry.test:ON Bundles/org.blueberry.uitest:ON ) set(_ctk_test_plugins # Testing/org.blueberry.core.runtime.tests:ON # Testing/org.blueberry.osgi.tests:ON ) if(BLUEBERRY_ENABLE_GUI_TESTING) # list(APPEND _ctk_test_plugins Testing/org.blueberry.ui.tests:ON) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_UI_APP}") get_target_property(_is_macosx_bundle ${OSGI_UI_APP} MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_UI_APP}.app/Contents/MacOS/${OSGI_UI_APP}") endif() endif() endif() set(BLUEBERRY_TESTING_PROVISIONING_FILE "${BlueBerry_BINARY_DIR}/BlueBerryTesting.provisioning") add_custom_target(BlueBerry) ctkMacroSetupPlugins(${_ctk_plugins} ${_ctk_testinfrastructure_plugins} ${_ctk_test_plugins} BUILD_OPTION_PREFIX BLUEBERRY_BUILD_ BUILD_ALL ${BLUEBERRY_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) set(BLUEBERRY_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/BlueBerry.provisioning") FunctionCreateProvisioningFile( FILE ${BLUEBERRY_PROVISIONING_FILE} PLUGINS ${_ctk_plugins} ) FunctionCreateProvisioningFile( FILE ${BLUEBERRY_TESTING_PROVISIONING_FILE} INCLUDE ${BLUEBERRY_PROVISIONING_FILE} PLUGINS ${_ctk_testinfrastructure_plugins} ${_ctk_test_plugins} ) if(${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES) add_dependencies(BlueBerry ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES}) endif() set_property(TARGET ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES} PROPERTY LABELS BlueBerry) set(BB_PLUGIN_USE_FILE "${BlueBerry_BINARY_DIR}/BlueBerryPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${BB_PLUGIN_USE_FILE}) else() file(REMOVE ${BB_PLUGIN_USE_FILE}) set(BB_PLUGIN_USE_FILE ) endif() # CTK Plugin Exports set(BB_PLUGIN_EXPORTS_FILE "${CMAKE_CURRENT_BINARY_DIR}/BlueBerryPluginExports.cmake") GetMyTargetLibraries("${${PROJECT_NAME}_PLUGIN_LIBRARIES}" my_plugin_targets) set(additional_export_targets mbilog PocoFoundation PocoUtil PocoXML) if(BLUEBERRY_BUILD_TESTING) list(APPEND additional_export_targets CppUnit) endif() export(TARGETS ${my_plugin_targets} ${additional_export_targets} FILE ${BB_PLUGIN_EXPORTS_FILE}) add_subdirectory(Documentation) configure_file(BlueBerryConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/BlueBerryConfig.cmake @ONLY) diff --git a/CMake/MITKDashboardSetup.cmake b/CMake/MITKDashboardSetup.cmake index 814e87bdfd..aa6fe9b405 100644 --- a/CMake/MITKDashboardSetup.cmake +++ b/CMake/MITKDashboardSetup.cmake @@ -1,125 +1,136 @@ # This file is intended to be included at the end of a custom MITKDashboardScript.TEMPLATE.cmake file list(APPEND CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}") # # Automatically determined properties # set(MY_OPERATING_SYSTEM "${CMAKE_HOST_SYSTEM}") # Windows 7, Linux-2.6.32, Darwin... site_name(CTEST_SITE) if(QT_BINARY_DIR) set(QT_QMAKE_EXECUTABLE "${QT_BINARY_DIR}/qmake") else() set(QT_QMAKE_EXECUTABLE "qmake") endif() execute_process(COMMAND ${QT_QMAKE_EXECUTABLE} --version OUTPUT_VARIABLE MY_QT_VERSION RESULT_VARIABLE qmake_error) if(qmake_error) message(FATAL_ERROR "Error when executing ${QT_QMAKE_EXECUTABLE} --version\n${qmake_error}") endif() string(REGEX REPLACE ".*Qt version ([0-9.]+) .*" "\\1" MY_QT_VERSION ${MY_QT_VERSION}) # # Project specific properties # if(NOT CTEST_BUILD_NAME) set(CTEST_BUILD_NAME "${MY_OPERATING_SYSTEM}-${MY_COMPILER}-Qt-${MY_QT_VERSION}-${CTEST_BUILD_CONFIGURATION}") endif() set(PROJECT_BUILD_DIR "MITK-build") set(CTEST_PATH "$ENV{PATH}") if(WIN32) set(VTK_BINARY_DIR "${CTEST_BINARY_DIRECTORY}/VTK-build/bin/${CTEST_BUILD_CONFIGURATION}") set(ITK_BINARY_DIR "${CTEST_BINARY_DIRECTORY}/ITK-build/bin/${CTEST_BUILD_CONFIGURATION}") set(BOOST_BINARY_DIR "${CTEST_BINARY_DIRECTORY}/Boost-src/stage/lib") set(GDCM_BINARY_DIR "${CTEST_BINARY_DIRECTORY}/GDCM-build/bin/${CTEST_BUILD_CONFIGURATION}") set(OPENCV_BINARY_DIR "${CTEST_BINARY_DIRECTORY}/OpenCV-build/bin/${CTEST_BUILD_CONFIGURATION}") set(BLUEBERRY_OSGI_DIR "${CTEST_BINARY_DIRECTORY}/MITK-build/bin/BlueBerry/org.blueberry.osgi/bin/${CTEST_BUILD_CONFIGURATION}") set(CTEST_PATH "${CTEST_PATH};${QT_BINARY_DIR};${VTK_BINARY_DIR};${ITK_BINARY_DIR};${BOOST_BINARY_DIR};${GDCM_BINARY_DIR};${OPENCV_BINARY_DIR};${BLUEBERRY_OSGI_DIR}") endif() set(ENV{PATH} "${CTEST_PATH}") set(SUPERBUILD_TARGETS "") # If the dashscript doesn't define a GIT_REPOSITORY variable, let's define it here. if(NOT DEFINED GIT_REPOSITORY OR GIT_REPOSITORY STREQUAL "") set(GIT_REPOSITORY "http://git.mitk.org/MITK.git") endif() # # Display build info # message("Site name: ${CTEST_SITE}") message("Build name: ${CTEST_BUILD_NAME}") message("Script Mode: ${SCRIPT_MODE}") message("Coverage: ${WITH_COVERAGE}, MemCheck: ${WITH_MEMCHECK}") # # Set initial cache options # if(CMAKE_GENERATOR MATCHES "[Mm]ake") set(CTEST_USE_LAUNCHERS 1) else() set(CTEST_USE_LAUNCHERS 0) endif() # Remove this if block after all dartclients work if(DEFINED ADDITIONNAL_CMAKECACHE_OPTION) message(WARNING "Rename ADDITIONNAL to ADDITIONAL in your dartlclient script: ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}") set(ADDITIONAL_CMAKECACHE_OPTION ${ADDITIONNAL_CMAKECACHE_OPTION}) endif() if(NOT DEFINED MITK_USE_Boost) set(MITK_USE_Boost 1) endif() if(NOT DEFINED MITK_USE_OpenCV) set(MITK_USE_OpenCV 1) endif() if(NOT DEFINED MITK_BUILD_ALL_APPS) set(MITK_BUILD_ALL_APPS TRUE) endif() +if(NOT DEFINED BLUEBERRY_BUILD_ALL_PLUGINS) + set(BLUEBERRY_BUILD_ALL_PLUGINS TRUE) +endif() + +if(NOT DEFINED MITK_BUILD_ALL_PLUGINS) + set(MITK_BUILD_ALL_PLUGINS TRUE) +endif() + +if(NOT DEFINED MITK_BUILD_EXAMPLES) + set(MITK_BUILD_EXAMPLES TRUE) +endif() + set(INITIAL_CMAKECACHE_OPTIONS " -BLUEBERRY_BUILD_TESTING:BOOL=TRUE -BLUEBERRY_BUILD_ALL_PLUGINS:BOOL=TRUE -MITK_BUILD_ALL_PLUGINS:BOOL=TRUE +BLUEBERRY_BUILD_ALL_PLUGINS:BOOL=${MITK_BUILD_ALL_PLUGINS} +MITK_BUILD_ALL_PLUGINS:BOOL=${MITK_BUILD_ALL_PLUGINS} MITK_BUILD_ALL_APPS:BOOL=${MITK_BUILD_ALL_APPS} -MITK_BUILD_EXAMPLES:BOOL=TRUE +MITK_BUILD_EXAMPLES:BOOL=${MITK_BUILD_EXAMPLES} SUPERBUILD_EXCLUDE_MITKBUILD_TARGET:BOOL=TRUE MITK_USE_Boost:BOOL=${MITK_USE_Boost} MITK_USE_OpenCV:BOOL=${MITK_USE_OpenCV} ${ADDITIONAL_CMAKECACHE_OPTION} ") # Write a cache file for populating the MITK initial cache (not the superbuild cache). # This can be used to provide variables which are not passed through the # superbuild process to the MITK configure step) if(MITK_INITIAL_CACHE) set(mitk_cache_file "${CTEST_SCRIPT_DIRECTORY}/mitk_initial_cache.txt") file(WRITE "${mitk_cache_file}" "${MITK_INITIAL_CACHE}") set(INITIAL_CMAKECACHE_OPTIONS "${INITIAL_CMAKECACHE_OPTIONS} MITK_INITIAL_CACHE_FILE:INTERNAL=${mitk_cache_file} ") endif() # # Download and include dashboard driver script # if(NOT DEFINED GIT_BRANCH OR GIT_BRANCH STREQUAL "") set(hb "HEAD") else() set(hb "refs/heads/${GIT_BRANCH}") endif() set(url "http://mitk.org/git/?p=MITK.git;a=blob_plain;f=CMake/MITKDashboardDriverScript.cmake;hb=${hb}") set(dest ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}.driver) downloadFile("${url}" "${dest}") include(${dest}) diff --git a/Core/Code/CppMicroServices/src/service/usServiceRegistration.cpp b/Core/Code/CppMicroServices/src/service/usServiceRegistration.cpp index 3a10639437..c945abe64d 100644 --- a/Core/Code/CppMicroServices/src/service/usServiceRegistration.cpp +++ b/Core/Code/CppMicroServices/src/service/usServiceRegistration.cpp @@ -1,232 +1,244 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #ifdef US_ENABLE_SERVICE_FACTORY_SUPPORT #include US_BASECLASS_HEADER #endif #include "usServiceRegistration.h" #include "usServiceRegistrationPrivate.h" #include "usServiceListenerEntry_p.h" #include "usServiceRegistry_p.h" #include "usServiceFactory.h" #include "usModulePrivate.h" #include "usCoreModuleContext_p.h" #include US_BEGIN_NAMESPACE typedef ServiceRegistrationPrivate::MutexLocker MutexLocker; ServiceRegistration::ServiceRegistration() : d(0) { } ServiceRegistration::ServiceRegistration(const ServiceRegistration& reg) : d(reg.d) { if (d) d->ref.Ref(); } ServiceRegistration::ServiceRegistration(ServiceRegistrationPrivate* registrationPrivate) : d(registrationPrivate) { if (d) d->ref.Ref(); } ServiceRegistration::ServiceRegistration(ModulePrivate* module, US_BASECLASS_NAME* service, const ServiceProperties& props) : d(new ServiceRegistrationPrivate(module, service, props)) { } ServiceRegistration::operator bool() const { return d != 0; } ServiceRegistration& ServiceRegistration::operator=(int null) { if (null == 0) { if (d && !d->ref.Deref()) { delete d; } d = 0; } return *this; } ServiceRegistration::~ServiceRegistration() { if (d && !d->ref.Deref()) delete d; } ServiceReference ServiceRegistration::GetReference() const { if (!d) throw std::logic_error("ServiceRegistration object invalid"); if (!d->available) throw std::logic_error("Service is unregistered"); return d->reference; } void ServiceRegistration::SetProperties(const ServiceProperties& props) { if (!d) throw std::logic_error("ServiceRegistration object invalid"); MutexLocker lock(d->eventLock); ServiceListeners::ServiceListenerEntries before; // TBD, optimize the locking of services { //MutexLocker lock2(d->module->coreCtx->globalFwLock); - MutexLocker lock3(d->propsLock); if (d->available) { // NYI! Optimize the MODIFIED_ENDMATCH code - int old_rank = any_cast(d->properties[ServiceConstants::SERVICE_RANKING()]); - d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, before, false); - const std::list& classes = ref_any_cast >(d->properties[ServiceConstants::OBJECTCLASS()]); - long int sid = any_cast(d->properties[ServiceConstants::SERVICE_ID()]); - d->properties = ServiceRegistry::CreateServiceProperties(props, classes, sid); - int new_rank = any_cast(d->properties[ServiceConstants::SERVICE_RANKING()]); + int old_rank = 0; + int new_rank = 0; + + std::list classes; + { + MutexLocker lock3(d->propsLock); + + Any any = d->properties[ServiceConstants::SERVICE_RANKING()]; + if (any.Type() == typeid(int)) old_rank = any_cast(any); + + d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, before, false); + classes = ref_any_cast >(d->properties[ServiceConstants::OBJECTCLASS()]); + long int sid = any_cast(d->properties[ServiceConstants::SERVICE_ID()]); + d->properties = ServiceRegistry::CreateServiceProperties(props, classes, sid); + + any = d->properties[ServiceConstants::SERVICE_RANKING()]; + if (any.Type() == typeid(int)) new_rank = any_cast(any); + } + if (old_rank != new_rank) { d->module->coreCtx->services.UpdateServiceRegistrationOrder(*this, classes); } } else { throw std::logic_error("Service is unregistered"); } } ServiceListeners::ServiceListenerEntries matchingListeners; d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, matchingListeners); d->module->coreCtx->listeners.ServiceChanged(matchingListeners, ServiceEvent(ServiceEvent::MODIFIED, d->reference), before); d->module->coreCtx->listeners.ServiceChanged(before, ServiceEvent(ServiceEvent::MODIFIED_ENDMATCH, d->reference)); } void ServiceRegistration::Unregister() { if (!d) throw std::logic_error("ServiceRegistration object invalid"); if (d->unregistering) return; // Silently ignore redundant unregistration. { MutexLocker lock(d->eventLock); if (d->unregistering) return; d->unregistering = true; if (d->available) { if (d->module) { d->module->coreCtx->services.RemoveServiceRegistration(*this); } } else { throw std::logic_error("Service is unregistered"); } } if (d->module) { ServiceListeners::ServiceListenerEntries listeners; d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, listeners); d->module->coreCtx->listeners.ServiceChanged( listeners, ServiceEvent(ServiceEvent::UNREGISTERING, d->reference)); } { MutexLocker lock(d->eventLock); { MutexLocker lock2(d->propsLock); d->available = false; #ifdef US_ENABLE_SERVICE_FACTORY_SUPPORT if (d->module) { ServiceRegistrationPrivate::ModuleToServicesMap::const_iterator end = d->serviceInstances.end(); for (ServiceRegistrationPrivate::ModuleToServicesMap::const_iterator i = d->serviceInstances.begin(); i != end; ++i) { US_BASECLASS_NAME* obj = i->second; try { // NYI, don't call inside lock dynamic_cast(d->service)->UngetService(i->first, *this, obj); } catch (const std::exception& /*ue*/) { US_WARN << "ServiceFactory UngetService implementation threw an exception"; } } } #endif d->module = 0; d->dependents.clear(); d->service = 0; d->serviceInstances.clear(); d->reference = 0; d->unregistering = false; } } } bool ServiceRegistration::operator<(const ServiceRegistration& o) const { if (!d) return true; return d->reference <(o.d->reference); } bool ServiceRegistration::operator==(const ServiceRegistration& registration) const { return d == registration.d; } ServiceRegistration& ServiceRegistration::operator=(const ServiceRegistration& registration) { ServiceRegistrationPrivate* curr_d = d; d = registration.d; if (d) d->ref.Ref(); if (curr_d && !curr_d->ref.Deref()) delete curr_d; return *this; } US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/src/service/usServiceRegistry.cpp b/Core/Code/CppMicroServices/src/service/usServiceRegistry.cpp index d27fcce1ff..5a49cdc7dd 100644 --- a/Core/Code/CppMicroServices/src/service/usServiceRegistry.cpp +++ b/Core/Code/CppMicroServices/src/service/usServiceRegistry.cpp @@ -1,335 +1,327 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #ifdef US_ENABLE_SERVICE_FACTORY_SUPPORT #include US_BASECLASS_HEADER #endif #include "usServiceRegistry_p.h" #include "usServiceFactory.h" #include "usServiceRegistry_p.h" #include "usServiceRegistrationPrivate.h" #include "usModulePrivate.h" #include "usCoreModuleContext_p.h" US_BEGIN_NAMESPACE typedef MutexLock MutexLocker; -struct ServiceRegistrationComparator -{ - bool operator()(const ServiceRegistration& a, const ServiceRegistration& b) const - { - return a < b; - } -}; - ServiceProperties ServiceRegistry::CreateServiceProperties(const ServiceProperties& in, const std::list& classes, long sid) { static long nextServiceID = 1; ServiceProperties props(in); if (!classes.empty()) { props.insert(std::make_pair(ServiceConstants::OBJECTCLASS(), classes)); } props.insert(std::make_pair(ServiceConstants::SERVICE_ID(), sid != -1 ? sid : nextServiceID++)); return props; } ServiceRegistry::ServiceRegistry(CoreModuleContext* coreCtx) : core(coreCtx) { } ServiceRegistry::~ServiceRegistry() { Clear(); } void ServiceRegistry::Clear() { services.clear(); serviceRegistrations.clear(); classServices.clear(); core = 0; } ServiceRegistration ServiceRegistry::RegisterService(ModulePrivate* module, const std::list& classes, US_BASECLASS_NAME* service, const ServiceProperties& properties) { if (service == 0) { throw std::invalid_argument("Can't register 0 as a service"); } // Check if service implements claimed classes and that they exist. for (std::list::const_iterator i = classes.begin(); i != classes.end(); ++i) { if (i->empty()) { throw std::invalid_argument("Can't register as null class"); } #ifdef US_ENABLE_SERVICE_FACTORY_SUPPORT if (!(dynamic_cast(service))) #endif { if (!CheckServiceClass(service, *i)) { std::string msg; std::stringstream ss(msg); ss << "Service class " << us_service_impl_name(service) << " is not an instance of " << (*i) << ". Maybe you forgot to export the RTTI information for the interface."; throw std::invalid_argument(msg); } } } ServiceRegistration res(module, service, CreateServiceProperties(properties, classes)); { MutexLocker lock(mutex); services.insert(std::make_pair(res, classes)); serviceRegistrations.push_back(res); for (std::list::const_iterator i = classes.begin(); i != classes.end(); ++i) { std::list& s = classServices[*i]; std::list::iterator ip = - std::lower_bound(s.begin(), s.end(), res, ServiceRegistrationComparator()); + std::lower_bound(s.begin(), s.end(), res); s.insert(ip, res); } } ServiceReference r = res.GetReference(); ServiceListeners::ServiceListenerEntries listeners; module->coreCtx->listeners.GetMatchingServiceListeners(r, listeners); module->coreCtx->listeners.ServiceChanged(listeners, ServiceEvent(ServiceEvent::REGISTERED, r)); return res; } void ServiceRegistry::UpdateServiceRegistrationOrder(const ServiceRegistration& sr, const std::list& classes) { MutexLocker lock(mutex); for (std::list::const_iterator i = classes.begin(); i != classes.end(); ++i) { std::list& s = classServices[*i]; - std::remove(s.begin(), s.end(), sr); - s.insert(std::lower_bound(s.begin(), s.end(), sr, ServiceRegistrationComparator()), sr); + s.erase(std::remove(s.begin(), s.end(), sr), s.end()); + s.insert(std::lower_bound(s.begin(), s.end(), sr), sr); } } bool ServiceRegistry::CheckServiceClass(US_BASECLASS_NAME* , const std::string& ) const { //return service->inherits(cls.toAscii()); // No possibility to check inheritance based on string literals. return true; } void ServiceRegistry::Get(const std::string& clazz, std::list& serviceRegs) const { MutexLocker lock(mutex); MapClassServices::const_iterator i = classServices.find(clazz); if (i != classServices.end()) { serviceRegs = i->second; } } ServiceReference ServiceRegistry::Get(ModulePrivate* module, const std::string& clazz) const { MutexLocker lock(mutex); try { std::list srs; Get_unlocked(clazz, "", module, srs); US_DEBUG << "get service ref " << clazz << " for module " << module->info.name << " = " << srs.size() << " refs"; if (!srs.empty()) { - return srs.front(); + return srs.back(); } } catch (const std::invalid_argument& ) { } return ServiceReference(); } void ServiceRegistry::Get(const std::string& clazz, const std::string& filter, ModulePrivate* module, std::list& res) const { MutexLocker lock(mutex); Get_unlocked(clazz, filter, module, res); } void ServiceRegistry::Get_unlocked(const std::string& clazz, const std::string& filter, ModulePrivate* /*module*/, std::list& res) const { std::list::const_iterator s; std::list::const_iterator send; std::list v; LDAPExpr ldap; if (clazz.empty()) { if (!filter.empty()) { ldap = LDAPExpr(filter); LDAPExpr::ObjectClassSet matched; if (ldap.GetMatchedObjectClasses(matched)) { v.clear(); for(LDAPExpr::ObjectClassSet::const_iterator className = matched.begin(); className != matched.end(); ++className) { MapClassServices::const_iterator i = classServices.find(*className); if (i != classServices.end()) { std::copy(i->second.begin(), i->second.end(), std::back_inserter(v)); } } if (!v.empty()) { s = v.begin(); send = v.end(); } else { return; } } else { s = serviceRegistrations.begin(); send = serviceRegistrations.end(); } } else { s = serviceRegistrations.begin(); send = serviceRegistrations.end(); } } else { MapClassServices::const_iterator it = classServices.find(clazz); if (it != classServices.end()) { s = it->second.begin(); send = it->second.end(); } else { return; } if (!filter.empty()) { ldap = LDAPExpr(filter); } } for (; s != send; ++s) { ServiceReference sri = s->GetReference(); if (filter.empty() || ldap.Evaluate(s->d->properties, false)) { res.push_back(sri); } } } void ServiceRegistry::RemoveServiceRegistration(const ServiceRegistration& sr) { MutexLocker lock(mutex); const std::list& classes = ref_any_cast >( sr.d->properties[ServiceConstants::OBJECTCLASS()]); services.erase(sr); serviceRegistrations.remove(sr); for (std::list::const_iterator i = classes.begin(); i != classes.end(); ++i) { std::list& s = classServices[*i]; if (s.size() > 1) { s.erase(std::remove(s.begin(), s.end(), sr), s.end()); } else { classServices.erase(*i); } } } void ServiceRegistry::GetRegisteredByModule(ModulePrivate* p, std::list& res) const { MutexLocker lock(mutex); for (std::list::const_iterator i = serviceRegistrations.begin(); i != serviceRegistrations.end(); ++i) { if (i->d->module == p) { res.push_back(*i); } } } void ServiceRegistry::GetUsedByModule(Module* p, std::list& res) const { MutexLocker lock(mutex); for (std::list::const_iterator i = serviceRegistrations.begin(); i != serviceRegistrations.end(); ++i) { if (i->d->IsUsedByModule(p)) { res.push_back(*i); } } } US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/test/usServiceRegistryTest.cpp b/Core/Code/CppMicroServices/test/usServiceRegistryTest.cpp index 74b5c19b3d..a2cbdf3507 100644 --- a/Core/Code/CppMicroServices/test/usServiceRegistryTest.cpp +++ b/Core/Code/CppMicroServices/test/usServiceRegistryTest.cpp @@ -1,79 +1,138 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include "usTestingMacros.h" #include #include #include #include US_BASECLASS_HEADER #include US_USE_NAMESPACE struct ITestServiceA { virtual ~ITestServiceA() {} }; US_DECLARE_SERVICE_INTERFACE(ITestServiceA, "org.cppmicroservices.testing.ITestServiceA") int TestMultipleServiceRegistrations() { struct TestServiceA : public US_BASECLASS_NAME, public ITestServiceA { }; ModuleContext* context = GetModuleContext(); TestServiceA s1; TestServiceA s2; ServiceRegistration reg1 = context->RegisterService(&s1); ServiceRegistration reg2 = context->RegisterService(&s2); std::list refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.size() == 2, "Testing for two registered ITestServiceA services") reg2.Unregister(); refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.size() == 1, "Testing for one registered ITestServiceA services") reg1.Unregister(); refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.empty(), "Testing for no ITestServiceA services") return EXIT_SUCCESS; } +int TestServicePropertiesUpdate() +{ + struct TestServiceA : public US_BASECLASS_NAME, public ITestServiceA + { + }; + + ModuleContext* context = GetModuleContext(); + + TestServiceA s1; + ServiceProperties props; + props["string"] = std::string("A std::string"); + props["bool"] = false; + const char* str = "A const char*"; + props["const char*"] = str; + + ServiceRegistration reg1 = context->RegisterService(&s1, props); + ServiceReference ref1 = context->GetServiceReference(); + + US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().size() == 1, "Testing service count") + US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty("bool")) == false, "Testing bool property") + + // register second service with higher rank + TestServiceA s2; + ServiceProperties props2; + props2[ServiceConstants::SERVICE_RANKING()] = 50; + + ServiceRegistration reg2 = context->RegisterService(&s2, props2); + + // Get the service with the highest rank, this should be s2. + ServiceReference ref2 = context->GetServiceReference(); + TestServiceA* service = dynamic_cast(context->GetService(ref2)); + US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank") + + props["bool"] = true; + // change the service ranking + props[ServiceConstants::SERVICE_RANKING()] = 100; + reg1.SetProperties(props); + + US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().size() == 2, "Testing service count") + US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty("bool")) == true, "Testing bool property") + US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty(ServiceConstants::SERVICE_RANKING())) == 100, "Testing updated ranking") + + // Service with the highest ranking should now be s1 + service = dynamic_cast(context->GetService(ref1)); + US_TEST_CONDITION_REQUIRED(service == &s1, "Testing highest service rank") + + reg1.Unregister(); + US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").size() == 1, "Testing service count") + + service = dynamic_cast(context->GetService(ref2)); + US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank") + + reg2.Unregister(); + US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().empty(), "Testing service count") + + return EXIT_SUCCESS; +} + int usServiceRegistryTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceRegistryTest"); US_TEST_CONDITION(TestMultipleServiceRegistrations() == EXIT_SUCCESS, "Testing service registrations: ") + US_TEST_CONDITION(TestServicePropertiesUpdate() == EXIT_SUCCESS, "Testing service property update: ") US_TEST_END() } diff --git a/Core/Code/DataManagement/mitkImage.cpp b/Core/Code/DataManagement/mitkImage.cpp index 397e027b78..bb3cf16547 100644 --- a/Core/Code/DataManagement/mitkImage.cpp +++ b/Core/Code/DataManagement/mitkImage.cpp @@ -1,1280 +1,1278 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkImage.h" #include "mitkImageStatisticsHolder.h" #include "mitkPixelTypeMultiplex.h" #include #include #define FILL_C_ARRAY( _arr, _size, _value) for(unsigned int i=0u; i<_size; i++) \ { _arr[i] = _value; } mitk::Image::Image() : m_Dimension(0), m_Dimensions(NULL), m_ImageDescriptor(NULL), m_OffsetTable(NULL), m_CompleteData(NULL), m_ImageStatistics(NULL) { m_Dimensions = new unsigned int[MAX_IMAGE_DIMENSIONS]; FILL_C_ARRAY( m_Dimensions, MAX_IMAGE_DIMENSIONS, 0u); m_Initialized = false; } mitk::Image::Image(const Image &other) : SlicedData(other), m_Dimension(0), m_Dimensions(NULL), m_ImageDescriptor(NULL), m_OffsetTable(NULL), m_CompleteData(NULL), m_ImageStatistics(NULL) { m_Dimensions = new unsigned int[MAX_IMAGE_DIMENSIONS]; FILL_C_ARRAY( m_Dimensions, MAX_IMAGE_DIMENSIONS, 0u); this->Initialize( other.GetPixelType(), other.GetDimension(), other.GetDimensions()); //Since the above called "Initialize" method doesn't take the geometry into account we need to set it //here manually this->SetGeometry(dynamic_cast(other.GetGeometry()->Clone().GetPointer())); if (this->GetDimension() > 3) { const unsigned int time_steps = this->GetDimension(3); for (unsigned int i = 0u; i < time_steps; ++i) { ImageDataItemPointer volume = const_cast(other).GetVolumeData(i); this->SetVolume(volume->GetData(), i); } } else { ImageDataItemPointer volume = const_cast(other).GetVolumeData(0); this->SetVolume(volume->GetData(), 0); } } mitk::Image::~Image() { Clear(); m_ReferenceCountLock.Lock(); m_ReferenceCount = 3; m_ReferenceCountLock.Unlock(); m_ReferenceCountLock.Lock(); m_ReferenceCount = 0; m_ReferenceCountLock.Unlock(); if(m_OffsetTable != NULL) delete [] m_OffsetTable; if(m_ImageStatistics != NULL) delete m_ImageStatistics; } const mitk::PixelType mitk::Image::GetPixelType(int n) const { return this->m_ImageDescriptor->GetChannelTypeById(n); } unsigned int mitk::Image::GetDimension() const { return m_Dimension; } unsigned int mitk::Image::GetDimension(int i) const { if((i>=0) && (i<(int)m_Dimension)) return m_Dimensions[i]; return 1; } void* mitk::Image::GetData() { if(m_Initialized==false) { if(GetSource().IsNull()) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } m_CompleteData=GetChannelData(); // update channel's data // if data was not available at creation point, the m_Data of channel descriptor is NULL // if data present, it won't be overwritten m_ImageDescriptor->GetChannelDescriptor(0).SetData(m_CompleteData->GetData()); return m_CompleteData->GetData(); } template void AccessPixel( const mitk::PixelType ptype, void* data, const unsigned int offset, double& value ) { value = 0.0; if( data == NULL ) return; if(ptype.GetBpe() != 24) { value = (double) (((T*) data)[ offset ]); } else { const unsigned int rgboffset = 3 * offset; double returnvalue = (((T*) data)[rgboffset ]); returnvalue += (((T*) data)[rgboffset + 1]); returnvalue += (((T*) data)[rgboffset + 2]); value = returnvalue; } } double mitk::Image::GetPixelValueByIndex(const mitk::Index3D &position, unsigned int timestep) { double value = 0; if (this->GetTimeSteps() < timestep) { timestep = this->GetTimeSteps(); } value = 0.0; const unsigned int* imageDims = this->m_ImageDescriptor->GetDimensions(); const mitk::PixelType ptype = this->m_ImageDescriptor->GetChannelTypeById(0); // Comparison ?>=0 not needed since all position[i] and timestep are unsigned int // (position[0]>=0 && position[1] >=0 && position[2]>=0 && timestep>=0) - // && - if ( (unsigned int)position[0] < imageDims[0] && (unsigned int)position[1] < imageDims[1] && - ( (imageDims[2] == 0) || (unsigned int)position[2] < imageDims[2]) // in case a 2D Image passed in, the third dimension could be set to 0 causing the if() to fail - /*&& (unsigned int)timestep < imageDims[3]*/ ) + // bug-11978 : we still need to catch index with negative values + if ( position[0] < 0 || + position[1] < 0 || + position[2] < 0 ) + { + MITK_WARN << "Given position ("<< position << ") is out of image range, returning 0." ; + } + // check if the given position is inside the index range of the image, the 3rd dimension needs to be compared only if the dimension is not 0 + else if ( (unsigned int)position[0] >= imageDims[0] || + (unsigned int)position[1] >= imageDims[1] || + ( imageDims[2] && (unsigned int)position[2] >= imageDims[2] )) + { + MITK_WARN << "Given position ("<< position << ") is out of image range, returning 0." ; + } + else { const unsigned int offset = position[0] + position[1]*imageDims[0] + position[2]*imageDims[0]*imageDims[1] + timestep*imageDims[0]*imageDims[1]*imageDims[2]; mitkPixelTypeMultiplex3( AccessPixel, ptype, this->GetData(), offset, value ); } return value; } double mitk::Image::GetPixelValueByWorldCoordinate(const mitk::Point3D& position, unsigned int timestep) { double value = 0.0; if (this->GetTimeSteps() < timestep) { timestep = this->GetTimeSteps(); } Index3D itkIndex; this->GetGeometry()->WorldToIndex(position, itkIndex); - const unsigned int* imageDims = this->m_ImageDescriptor->GetDimensions(); - const mitk::PixelType ptype = this->m_ImageDescriptor->GetChannelTypeById(0); - - //if ( (itkIndex[0]>=0 && itkIndex[1] >=0 && itkIndex[2]>=0 && timestep>=0) - // && - // lines above taken from comparison since always true due to unsigned type - if (((unsigned int)itkIndex[0] < imageDims[0] && - (unsigned int)itkIndex[1] < imageDims[1] && - (imageDims[2] == 0) ) || ((unsigned int)itkIndex[2] < imageDims[2])) // in case a 2D Image passed in, the third dimension could be set to 0 causing the if() to fail - { - const unsigned int offset = itkIndex[0] + itkIndex[1]*imageDims[0] + itkIndex[2]*imageDims[0]*imageDims[1] + timestep*imageDims[0]*imageDims[1]*imageDims[2]; - - mitkPixelTypeMultiplex3( AccessPixel, ptype, this->GetData(), offset, value ); - } + value = this->GetPixelValueByIndex( itkIndex, timestep); return value; } vtkImageData* mitk::Image::GetVtkImageData(int t, int n) { if(m_Initialized==false) { if(GetSource().IsNull()) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } ImageDataItemPointer volume=GetVolumeData(t, n); if(volume.GetPointer()==NULL || volume->GetVtkImageData() == NULL) return NULL; float *fspacing = const_cast(GetSlicedGeometry(t)->GetFloatSpacing()); double dspacing[3] = {fspacing[0],fspacing[1],fspacing[2]}; volume->GetVtkImageData()->SetSpacing( dspacing ); return volume->GetVtkImageData(); } mitk::Image::ImageDataItemPointer mitk::Image::GetSliceData(int s, int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidSlice(s,t,n)==false) return NULL; const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); // slice directly available? int pos=GetSliceIndex(s,t,n); if(m_Slices[pos].GetPointer()!=NULL) return m_Slices[pos]; // is slice available as part of a volume that is available? ImageDataItemPointer sl, ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) { sl=new ImageDataItem(*vol, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(ptypeSize)); sl->SetComplete(true); return m_Slices[pos]=sl; } // is slice available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) { sl=new ImageDataItem(*ch, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, (((size_t) s)*m_OffsetTable[2]+((size_t) t)*m_OffsetTable[3])*(ptypeSize)); sl->SetComplete(true); return m_Slices[pos]=sl; } // slice is unavailable. Can we calculate it? if((GetSource().IsNotNull()) && (GetSource()->Updating()==false)) { // ... wir mussen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, s); m_RequestedRegion.SetIndex(3, t); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, 1); m_RequestedRegion.SetSize(3, 1); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); if(IsSliceSet(s,t,n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetSliceData(s,t,n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateSliceData(s,t,n,data,importMemoryManagement); item->SetComplete(true); return item; } } mitk::Image::ImageDataItemPointer mitk::Image::GetVolumeData(int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidVolume(t,n)==false) return NULL; ImageDataItemPointer ch, vol; // volume directly available? int pos=GetVolumeIndex(t,n); vol=m_Volumes[pos]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return vol; const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); // is volume available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) { vol=new ImageDataItem(*ch, m_ImageDescriptor, 3, data, importMemoryManagement == ManageMemory, (((size_t) t)*m_OffsetTable[3])*(ptypeSize)); vol->SetComplete(true); return m_Volumes[pos]=vol; } // let's see if all slices of the volume are set, so that we can (could) combine them to a volume bool complete=true; unsigned int s; for(s=0;sSetComplete(true); } else { mitk::PixelType chPixelType = this->m_ImageDescriptor->GetChannelTypeById(n); vol=m_Volumes[pos]; // ok, let's combine the slices! if(vol.GetPointer()==NULL) vol=new ImageDataItem( chPixelType, 3, m_Dimensions, NULL, true); vol->SetComplete(true); size_t size=m_OffsetTable[2]*(ptypeSize); for(s=0;sGetParent()!=vol) { // copy data of slices in volume size_t offset = ((size_t) s)*size; std::memcpy(static_cast(vol->GetData())+offset, sl->GetData(), size); // FIXME mitkIpPicDescriptor * pic = sl->GetPicDescriptor(); // replace old slice with reference to volume sl=new ImageDataItem(*vol, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*size); sl->SetComplete(true); //mitkIpFuncCopyTags(sl->GetPicDescriptor(), pic); m_Slices[posSl]=sl; } } //if(vol->GetPicDescriptor()->info->tags_head==NULL) // mitkIpFuncCopyTags(vol->GetPicDescriptor(), m_Slices[GetSliceIndex(0,t,n)]->GetPicDescriptor()); } return m_Volumes[pos]=vol; } // volume is unavailable. Can we calculate it? if((GetSource().IsNotNull()) && (GetSource()->Updating()==false)) { // ... wir muessen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, 0); m_RequestedRegion.SetIndex(3, t); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, m_Dimensions[2]); m_RequestedRegion.SetSize(3, 1); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); if(IsVolumeSet(t,n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetVolumeData(t,n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateVolumeData(t,n,data,importMemoryManagement); item->SetComplete(true); return item; } } mitk::Image::ImageDataItemPointer mitk::Image::GetChannelData(int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidChannel(n)==false) return NULL; ImageDataItemPointer ch, vol; ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return ch; // let's see if all volumes are set, so that we can (could) combine them to a channel if(IsChannelSet(n)) { // if there is only one time frame we do not need to combine anything if(m_Dimensions[3]<=1) { vol=GetVolumeData(0,n,data,importMemoryManagement); ch=new ImageDataItem(*vol, m_ImageDescriptor, m_ImageDescriptor->GetNumberOfDimensions(), data, importMemoryManagement == ManageMemory); ch->SetComplete(true); } else { const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); ch=m_Channels[n]; // ok, let's combine the volumes! if(ch.GetPointer()==NULL) ch=new ImageDataItem(this->m_ImageDescriptor, NULL, true); ch->SetComplete(true); size_t size=m_OffsetTable[m_Dimension-1]*(ptypeSize); unsigned int t; ImageDataItemPointerArray::iterator slicesIt = m_Slices.begin()+n*m_Dimensions[2]*m_Dimensions[3]; for(t=0;tGetParent()!=ch) { // copy data of volume in channel size_t offset = ((size_t) t)*m_OffsetTable[3]*(ptypeSize); std::memcpy(static_cast(ch->GetData())+offset, vol->GetData(), size); // REVEIW FIX mitkIpPicDescriptor * pic = vol->GetPicDescriptor(); // replace old volume with reference to channel vol=new ImageDataItem(*ch, m_ImageDescriptor, 3, data, importMemoryManagement == ManageMemory, offset); vol->SetComplete(true); //mitkIpFuncCopyTags(vol->GetPicDescriptor(), pic); m_Volumes[posVol]=vol; // get rid of slices - they may point to old volume ImageDataItemPointer dnull=NULL; for(unsigned int i = 0; i < m_Dimensions[2]; ++i, ++slicesIt) { assert(slicesIt != m_Slices.end()); *slicesIt = dnull; } } } // REVIEW FIX // if(ch->GetPicDescriptor()->info->tags_head==NULL) // mitkIpFuncCopyTags(ch->GetPicDescriptor(), m_Volumes[GetVolumeIndex(0,n)]->GetPicDescriptor()); } return m_Channels[n]=ch; } // channel is unavailable. Can we calculate it? if((GetSource().IsNotNull()) && (GetSource()->Updating()==false)) { // ... wir muessen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, 0); m_RequestedRegion.SetIndex(3, 0); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, m_Dimensions[2]); m_RequestedRegion.SetSize(3, m_Dimensions[3]); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); // did it work? if(IsChannelSet(n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetChannelData(n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateChannelData(n,data,importMemoryManagement); item->SetComplete(true); return item; } } bool mitk::Image::IsSliceSet(int s, int t, int n) const { if(IsValidSlice(s,t,n)==false) return false; if(m_Slices[GetSliceIndex(s,t,n)].GetPointer()!=NULL) return true; ImageDataItemPointer ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return true; ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return true; return false; } bool mitk::Image::IsVolumeSet(int t, int n) const { if(IsValidVolume(t,n)==false) return false; ImageDataItemPointer ch, vol; // volume directly available? vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return true; // is volume available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return true; // let's see if all slices of the volume are set, so that we can (could) combine them to a volume unsigned int s; for(s=0;sIsComplete())) return true; // let's see if all volumes are set, so that we can (could) combine them to a channel unsigned int t; for(t=0;t(data), s, t, n, CopyMemory); } bool mitk::Image::SetVolume(const void *data, int t, int n) { // const_cast is no risk for ImportMemoryManagementType == CopyMemory return SetImportVolume(const_cast(data), t, n, CopyMemory); } bool mitk::Image::SetChannel(const void *data, int n) { // const_cast is no risk for ImportMemoryManagementType == CopyMemory return SetImportChannel(const_cast(data), n, CopyMemory); } bool mitk::Image::SetImportSlice(void *data, int s, int t, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidSlice(s,t,n)==false) return false; ImageDataItemPointer sl; const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); if(IsSliceSet(s,t,n)) { sl=GetSliceData(s,t,n,data,importMemoryManagement); if(sl->GetManageMemory()==false) { sl=AllocateSliceData(s,t,n,data,importMemoryManagement); if(sl.GetPointer()==NULL) return false; } if ( sl->GetData() != data ) std::memcpy(sl->GetData(), data, m_OffsetTable[2]*(ptypeSize)); sl->Modified(); //we have changed the data: call Modified()! Modified(); } else { sl=AllocateSliceData(s,t,n,data,importMemoryManagement); if(sl.GetPointer()==NULL) return false; if ( sl->GetData() != data ) std::memcpy(sl->GetData(), data, m_OffsetTable[2]*(ptypeSize)); //we just added a missing slice, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetImportVolume(void *data, int t, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidVolume(t,n)==false) return false; const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); ImageDataItemPointer vol; if(IsVolumeSet(t,n)) { vol=GetVolumeData(t,n,data,importMemoryManagement); if(vol->GetManageMemory()==false) { vol=AllocateVolumeData(t,n,data,importMemoryManagement); if(vol.GetPointer()==NULL) return false; } if ( vol->GetData() != data ) std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(ptypeSize)); vol->Modified(); vol->SetComplete(true); //we have changed the data: call Modified()! Modified(); } else { vol=AllocateVolumeData(t,n,data,importMemoryManagement); if(vol.GetPointer()==NULL) return false; if ( vol->GetData() != data ) { std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(ptypeSize)); } vol->SetComplete(true); this->m_ImageDescriptor->GetChannelDescriptor(n).SetData( vol->GetData() ); //we just added a missing Volume, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetImportChannel(void *data, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidChannel(n)==false) return false; // channel descriptor const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); ImageDataItemPointer ch; if(IsChannelSet(n)) { ch=GetChannelData(n,data,importMemoryManagement); if(ch->GetManageMemory()==false) { ch=AllocateChannelData(n,data,importMemoryManagement); if(ch.GetPointer()==NULL) return false; } if ( ch->GetData() != data ) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(ptypeSize)); ch->Modified(); ch->SetComplete(true); //we have changed the data: call Modified()! Modified(); } else { ch=AllocateChannelData(n,data,importMemoryManagement); if(ch.GetPointer()==NULL) return false; if ( ch->GetData() != data ) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(ptypeSize)); ch->SetComplete(true); this->m_ImageDescriptor->GetChannelDescriptor(n).SetData( ch->GetData() ); //we just added a missing Channel, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } void mitk::Image::Initialize() { ImageDataItemPointerArray::iterator it, end; for( it=m_Slices.begin(), end=m_Slices.end(); it!=end; ++it ) { (*it)=NULL; } for( it=m_Volumes.begin(), end=m_Volumes.end(); it!=end; ++it ) { (*it)=NULL; } for( it=m_Channels.begin(), end=m_Channels.end(); it!=end; ++it ) { (*it)=NULL; } m_CompleteData = NULL; if( m_ImageStatistics == NULL) { m_ImageStatistics = new mitk::ImageStatisticsHolder( this ); } SetRequestedRegionToLargestPossibleRegion(); } void mitk::Image::Initialize(const mitk::ImageDescriptor::Pointer inDesc) { // store the descriptor this->m_ImageDescriptor = inDesc; // initialize image this->Initialize( inDesc->GetChannelDescriptor(0).GetPixelType(), inDesc->GetNumberOfDimensions(), inDesc->GetDimensions(), 1 ); } void mitk::Image::Initialize(const mitk::PixelType& type, unsigned int dimension, const unsigned int *dimensions, unsigned int channels) { Clear(); m_Dimension=dimension; if(!dimensions) itkExceptionMacro(<< "invalid zero dimension image"); unsigned int i; for(i=0;im_ImageDescriptor = mitk::ImageDescriptor::New(); this->m_ImageDescriptor->Initialize( this->m_Dimensions, this->m_Dimension ); for(i=0;i<4;++i) { m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize (i, m_Dimensions[i]); } m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize(i, channels); if(m_LargestPossibleRegion.GetNumberOfPixels()==0) { delete [] m_Dimensions; m_Dimensions = NULL; return; } for( unsigned int i=0u; im_ImageDescriptor->AddNewChannel( type ); } PlaneGeometry::Pointer planegeometry = PlaneGeometry::New(); planegeometry->InitializeStandardPlane(m_Dimensions[0], m_Dimensions[1]); SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); slicedGeometry->InitializeEvenlySpaced(planegeometry, m_Dimensions[2]); if(dimension>=4) { TimeBounds timebounds; timebounds[0] = 0.0; timebounds[1] = 1.0; slicedGeometry->SetTimeBounds(timebounds); } TimeSlicedGeometry::Pointer timeSliceGeometry = TimeSlicedGeometry::New(); timeSliceGeometry->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); timeSliceGeometry->ImageGeometryOn(); SetGeometry(timeSliceGeometry); ImageDataItemPointer dnull=NULL; m_Channels.assign(GetNumberOfChannels(), dnull); m_Volumes.assign(GetNumberOfChannels()*m_Dimensions[3], dnull); m_Slices.assign(GetNumberOfChannels()*m_Dimensions[3]*m_Dimensions[2], dnull); ComputeOffsetTable(); Initialize(); m_Initialized = true; } void mitk::Image::Initialize(const mitk::PixelType& type, const mitk::Geometry3D& geometry, unsigned int channels, int tDim ) { unsigned int dimensions[5]; dimensions[0] = (unsigned int)(geometry.GetExtent(0)+0.5); dimensions[1] = (unsigned int)(geometry.GetExtent(1)+0.5); dimensions[2] = (unsigned int)(geometry.GetExtent(2)+0.5); dimensions[3] = 0; dimensions[4] = 0; unsigned int dimension = 2; if ( dimensions[2] > 1 ) dimension = 3; if ( tDim > 0) { dimensions[3] = tDim; } else { const mitk::TimeSlicedGeometry* timeGeometry = dynamic_cast(&geometry); if ( timeGeometry != NULL ) { dimensions[3] = timeGeometry->GetTimeSteps(); } } if ( dimensions[3] > 1 ) dimension = 4; Initialize( type, dimension, dimensions, channels ); SetGeometry(static_cast(geometry.Clone().GetPointer())); mitk::BoundingBox::BoundsArrayType bounds = geometry.GetBoundingBox()->GetBounds(); if( (bounds[0] != 0.0) || (bounds[2] != 0.0) || (bounds[4] != 0.0) ) { SlicedGeometry3D* slicedGeometry = GetSlicedGeometry(0); mitk::Point3D origin; origin.Fill(0.0); slicedGeometry->IndexToWorld(origin, origin); bounds[1]-=bounds[0]; bounds[3]-=bounds[2]; bounds[5]-=bounds[4]; bounds[0] = 0.0; bounds[2] = 0.0; bounds[4] = 0.0; this->m_ImageDescriptor->Initialize( this->m_Dimensions, this->m_Dimension ); slicedGeometry->SetBounds(bounds); slicedGeometry->GetIndexToWorldTransform()->SetOffset(origin.Get_vnl_vector().data_block()); GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); } } void mitk::Image::Initialize(const mitk::PixelType& type, int sDim, const mitk::Geometry2D& geometry2d, bool flipped, unsigned int channels, int tDim ) { SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); slicedGeometry->InitializeEvenlySpaced(static_cast(geometry2d.Clone().GetPointer()), sDim, flipped); Initialize(type, *slicedGeometry, channels, tDim); } void mitk::Image::Initialize(const mitk::Image* image) { Initialize(image->GetPixelType(), *image->GetTimeSlicedGeometry()); } void mitk::Image::Initialize(vtkImageData* vtkimagedata, int channels, int tDim, int sDim) { if(vtkimagedata==NULL) return; m_Dimension=vtkimagedata->GetDataDimension(); unsigned int i, *tmpDimensions=new unsigned int[m_Dimension>4?m_Dimension:4]; for(i=0;iGetDimensions()[i]; if(m_Dimension<4) { unsigned int *p; for(i=0,p=tmpDimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } if(sDim>=0) { tmpDimensions[2]=sDim; if(m_Dimension < 3) m_Dimension = 3; } if(tDim>=0) { tmpDimensions[3]=tDim; if(m_Dimension < 4) m_Dimension = 4; } switch ( vtkimagedata->GetScalarType() ) { case VTK_BIT: case VTK_CHAR: //pixelType.Initialize(typeid(char), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_UNSIGNED_CHAR: //pixelType.Initialize(typeid(unsigned char), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_SHORT: //pixelType.Initialize(typeid(short), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_UNSIGNED_SHORT: //pixelType.Initialize(typeid(unsigned short), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_INT: //pixelType.Initialize(typeid(int), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_UNSIGNED_INT: //pixelType.Initialize(typeid(unsigned int), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_LONG: //pixelType.Initialize(typeid(long), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_UNSIGNED_LONG: //pixelType.Initialize(typeid(unsigned long), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_FLOAT: //pixelType.Initialize(typeid(float), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_DOUBLE: //pixelType.Initialize(typeid(double), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; default: break; } /* Initialize(pixelType, m_Dimension, tmpDimensions, channels); */ const double *spacinglist = vtkimagedata->GetSpacing(); Vector3D spacing; FillVector3D(spacing, spacinglist[0], 1.0, 1.0); if(m_Dimension>=2) spacing[1]=spacinglist[1]; if(m_Dimension>=3) spacing[2]=spacinglist[2]; // access origin of vtkImage Point3D origin; vtkFloatingPointType vtkorigin[3]; vtkimagedata->GetOrigin(vtkorigin); FillVector3D(origin, vtkorigin[0], 0.0, 0.0); if(m_Dimension>=2) origin[1]=vtkorigin[1]; if(m_Dimension>=3) origin[2]=vtkorigin[2]; SlicedGeometry3D* slicedGeometry = GetSlicedGeometry(0); // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = static_cast(slicedGeometry->GetGeometry2D(0)); planeGeometry->SetOrigin(origin); // re-initialize SlicedGeometry3D slicedGeometry->SetOrigin(origin); slicedGeometry->SetSpacing(spacing); GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); delete [] tmpDimensions; } bool mitk::Image::IsValidSlice(int s, int t, int n) const { if(m_Initialized) return ((s>=0) && (s<(int)m_Dimensions[2]) && (t>=0) && (t< (int) m_Dimensions[3]) && (n>=0) && (n< (int)GetNumberOfChannels())); else return false; } bool mitk::Image::IsValidVolume(int t, int n) const { if(m_Initialized) return IsValidSlice(0, t, n); else return false; } bool mitk::Image::IsValidChannel(int n) const { if(m_Initialized) return IsValidSlice(0, 0, n); else return false; } void mitk::Image::ComputeOffsetTable() { if(m_OffsetTable!=NULL) delete [] m_OffsetTable; m_OffsetTable=new size_t[m_Dimension>4 ? m_Dimension+1 : 4+1]; unsigned int i; size_t num=1; m_OffsetTable[0] = 1; for (i=0; i < m_Dimension; ++i) { num *= m_Dimensions[i]; m_OffsetTable[i+1] = num; } for (;i < 4; ++i) m_OffsetTable[i+1] = num; } bool mitk::Image::IsValidTimeStep(int t) const { return ( ( m_Dimension >= 4 && t <= (int)m_Dimensions[3] && t > 0 ) || (t == 0) ); } void mitk::Image::Expand(unsigned int timeSteps) { if(timeSteps < 1) itkExceptionMacro(<< "Invalid timestep in Image!"); Superclass::Expand(timeSteps); } int mitk::Image::GetSliceIndex(int s, int t, int n) const { if(IsValidSlice(s,t,n)==false) return false; return ((size_t)s)+((size_t) t)*m_Dimensions[2]+((size_t) n)*m_Dimensions[3]*m_Dimensions[2]; //?? } int mitk::Image::GetVolumeIndex(int t, int n) const { if(IsValidVolume(t,n)==false) return false; return ((size_t)t)+((size_t) n)*m_Dimensions[3]; //?? } mitk::Image::ImageDataItemPointer mitk::Image::AllocateSliceData(int s, int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { int pos; pos=GetSliceIndex(s,t,n); const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); // is slice available as part of a volume that is available? ImageDataItemPointer sl, ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if(vol.GetPointer()!=NULL) { sl=new ImageDataItem(*vol, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(ptypeSize)); sl->SetComplete(true); return m_Slices[pos]=sl; } // is slice available as part of a channel that is available? ch=m_Channels[n]; if(ch.GetPointer()!=NULL) { sl=new ImageDataItem(*ch, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, (((size_t) s)*m_OffsetTable[2]+((size_t) t)*m_OffsetTable[3])*(ptypeSize)); sl->SetComplete(true); return m_Slices[pos]=sl; } // allocate new volume (instead of a single slice to keep data together!) m_Volumes[GetVolumeIndex(t,n)]=vol=AllocateVolumeData(t,n,NULL,importMemoryManagement); sl=new ImageDataItem(*vol, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(ptypeSize)); sl->SetComplete(true); return m_Slices[pos]=sl; ////ALTERNATIVE: //// allocate new slice //sl=new ImageDataItem(*m_PixelType, 2, m_Dimensions); //m_Slices[pos]=sl; //return vol; } mitk::Image::ImageDataItemPointer mitk::Image::AllocateVolumeData(int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { int pos; pos=GetVolumeIndex(t,n); const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); // is volume available as part of a channel that is available? ImageDataItemPointer ch, vol; ch=m_Channels[n]; if(ch.GetPointer()!=NULL) { vol=new ImageDataItem(*ch, m_ImageDescriptor, 3, data,importMemoryManagement == ManageMemory, (((size_t) t)*m_OffsetTable[3])*(ptypeSize)); return m_Volumes[pos]=vol; } mitk::PixelType chPixelType = this->m_ImageDescriptor->GetChannelTypeById(n); // allocate new volume if(importMemoryManagement == CopyMemory) { vol=new ImageDataItem( chPixelType, 3, m_Dimensions, NULL, true); if(data != NULL) std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(ptypeSize)); } else { vol=new ImageDataItem( chPixelType, 3, m_Dimensions, data, importMemoryManagement == ManageMemory); } m_Volumes[pos]=vol; return vol; } mitk::Image::ImageDataItemPointer mitk::Image::AllocateChannelData(int n, void *data, ImportMemoryManagementType importMemoryManagement) { ImageDataItemPointer ch; // allocate new channel if(importMemoryManagement == CopyMemory) { const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); ch=new ImageDataItem(this->m_ImageDescriptor, NULL, true); if(data != NULL) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(ptypeSize)); } else { ch=new ImageDataItem(this->m_ImageDescriptor, data, importMemoryManagement == ManageMemory); } m_Channels[n]=ch; return ch; } unsigned int* mitk::Image::GetDimensions() const { return m_Dimensions; } void mitk::Image::Clear() { Superclass::Clear(); delete [] m_Dimensions; m_Dimensions = NULL; } void mitk::Image::SetGeometry(Geometry3D* aGeometry3D) { // Please be aware of the 0.5 offset/pixel-center issue! See Geometry documentation for further information if(aGeometry3D->GetImageGeometry()==false) { MITK_INFO << "WARNING: Applied a non-image geometry onto an image. Please be SURE that this geometry is pixel-center-based! If it is not, you need to call Geometry3D->ChangeImageGeometryConsideringOriginOffset(true) before calling image->setGeometry(..)\n"; } Superclass::SetGeometry(aGeometry3D); GetTimeSlicedGeometry()->ImageGeometryOn(); } void mitk::Image::PrintSelf(std::ostream& os, itk::Indent indent) const { unsigned char i; if(m_Initialized) { os << indent << " Dimension: " << m_Dimension << std::endl; os << indent << " Dimensions: "; for(i=0; i < m_Dimension; ++i) os << GetDimension(i) << " "; os << std::endl; for(unsigned int ch=0; ch < this->m_ImageDescriptor->GetNumberOfChannels(); ch++) { mitk::PixelType chPixelType = this->m_ImageDescriptor->GetChannelTypeById(ch); os << indent << " Channel: " << this->m_ImageDescriptor->GetChannelName(ch) << std::endl; os << indent << " PixelType: " << chPixelType.GetTypeId().name() << std::endl; os << indent << " BitsPerElement: " << chPixelType.GetSize() << std::endl; os << indent << " NumberOfComponents: " << chPixelType.GetNumberOfComponents() << std::endl; os << indent << " BitsPerComponent: " << chPixelType.GetBitsPerComponent() << std::endl; } } else { os << indent << " Image not initialized: m_Initialized: false" << std::endl; } Superclass::PrintSelf(os,indent); } bool mitk::Image::IsRotated() const { const mitk::Geometry3D* geo = this->GetGeometry(); bool ret = false; if(geo) { const vnl_matrix_fixed & mx = geo->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); float ref = 0; for(short k = 0; k < 3; ++k) ref += mx[k][k]; ref/=1000; // Arbitrary value; if a non-diagonal (nd) element is bigger then this, matrix is considered nd. for(short i = 0; i < 3; ++i) { for(short j = 0; j < 3; ++j) { if(i != j) { if(std::abs(mx[i][j]) > ref) // matrix is nd ret = true; } } } } return ret; } #include "mitkImageStatisticsHolder.h" //##Documentation mitk::ScalarType mitk::Image::GetScalarValueMin(int t) const { return m_ImageStatistics->GetScalarValueMin(t); } //##Documentation //## \brief Get the maximum for scalar images mitk::ScalarType mitk::Image::GetScalarValueMax(int t) const { return m_ImageStatistics->GetScalarValueMax(t); } //##Documentation //## \brief Get the second smallest value for scalar images mitk::ScalarType mitk::Image::GetScalarValue2ndMin(int t) const { return m_ImageStatistics->GetScalarValue2ndMin(t); } mitk::ScalarType mitk::Image::GetScalarValueMinNoRecompute( unsigned int t ) const { return m_ImageStatistics->GetScalarValueMinNoRecompute(t); } mitk::ScalarType mitk::Image::GetScalarValue2ndMinNoRecompute( unsigned int t ) const { return m_ImageStatistics->GetScalarValue2ndMinNoRecompute(t); } mitk::ScalarType mitk::Image::GetScalarValue2ndMax(int t) const { return m_ImageStatistics->GetScalarValue2ndMax(t); } mitk::ScalarType mitk::Image::GetScalarValueMaxNoRecompute( unsigned int t) const { return m_ImageStatistics->GetScalarValueMaxNoRecompute(t); } mitk::ScalarType mitk::Image::GetScalarValue2ndMaxNoRecompute( unsigned int t ) const { return m_ImageStatistics->GetScalarValue2ndMaxNoRecompute(t); } mitk::ScalarType mitk::Image::GetCountOfMinValuedVoxels(int t ) const { return m_ImageStatistics->GetCountOfMinValuedVoxels(t); } mitk::ScalarType mitk::Image::GetCountOfMaxValuedVoxels(int t) const { return m_ImageStatistics->GetCountOfMaxValuedVoxels(t); } unsigned int mitk::Image::GetCountOfMaxValuedVoxelsNoRecompute( unsigned int t ) const { return m_ImageStatistics->GetCountOfMaxValuedVoxelsNoRecompute(t); } unsigned int mitk::Image::GetCountOfMinValuedVoxelsNoRecompute( unsigned int t ) const { return m_ImageStatistics->GetCountOfMinValuedVoxelsNoRecompute(t); } diff --git a/Core/Code/Interactions/StateMachine.xml b/Core/Code/Interactions/StateMachine.xml index f4585e53f7..ee9103b3d5 100644 --- a/Core/Code/Interactions/StateMachine.xml +++ b/Core/Code/Interactions/StateMachine.xml @@ -1,3913 +1,3954 @@ - + + + + + + + + + + + + + - + - - - + + + - + - + - + - + - + - - - - + + + + - - - - + + + + - - - - - - + + + + + + - - - - - - - - + + + + + + + + - + - + - - - + + + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + + + + + + + + + + + + diff --git a/Core/Code/Interactions/mitkMouseModeSwitcher.cpp b/Core/Code/Interactions/mitkMouseModeSwitcher.cpp index 8f989c952c..038faad398 100644 --- a/Core/Code/Interactions/mitkMouseModeSwitcher.cpp +++ b/Core/Code/Interactions/mitkMouseModeSwitcher.cpp @@ -1,191 +1,191 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkMouseModeSwitcher.h" #include "mitkDisplayInteractor.h" #include "mitkDisplayVectorInteractor.h" #include "mitkDisplayVectorInteractorLevelWindow.h" #include "mitkDisplayVectorInteractorScroll.h" mitk::MouseModeSwitcher::MouseModeSwitcher( mitk::GlobalInteraction* gi ) : m_GlobalInteraction( gi ) , m_ActiveInteractionScheme( MITK ) , m_ActiveMouseMode( MousePointer ) , m_LeftMouseButtonHandler( NULL ) { assert(gi); this->InitializeListeners(); this->SetInteractionScheme( m_ActiveInteractionScheme ); } mitk::MouseModeSwitcher::~MouseModeSwitcher() { } void mitk::MouseModeSwitcher::InitializeListeners() { mitk::DisplayVectorInteractor::Pointer moveAndZoomInteractor = mitk::DisplayVectorInteractor::New( "moveNzoom", new mitk::DisplayInteractor() ); mitk::StateMachine::Pointer listener = moveAndZoomInteractor.GetPointer(); m_ListenersForMITK.push_back( listener ); mitk::DisplayVectorInteractorScroll::Pointer scrollInteractor = mitk::DisplayVectorInteractorScroll::New( - "MiddleClickScroll", new mitk::DisplayInteractor() ); + "alternativeScroll", new mitk::DisplayInteractor() ); listener = scrollInteractor; m_ListenersForPACS.push_back( listener ); - mitk::DisplayVectorInteractorLevelWindow::Pointer lwInteractor = mitk::DisplayVectorInteractorLevelWindow::New("RightClickLevelWindow"); + mitk::DisplayVectorInteractorLevelWindow::Pointer lwInteractor = mitk::DisplayVectorInteractorLevelWindow::New("alternativeLevelWindow"); listener = lwInteractor; m_ListenersForPACS.push_back( listener ); mitk::DisplayVectorInteractor::Pointer panInteractor = mitk::DisplayVectorInteractor::New( - "ShiftClickPan", new mitk::DisplayInteractor() ); + "alternativePan", new mitk::DisplayInteractor() ); listener = panInteractor; m_ListenersForPACS.push_back( listener ); mitk::DisplayVectorInteractor::Pointer crtlZoomInteractor = mitk::DisplayVectorInteractor::New( - "CtrlZoom", new mitk::DisplayInteractor() ); + "alternativeZoom", new mitk::DisplayInteractor() ); listener = crtlZoomInteractor; m_ListenersForPACS.push_back( listener ); } void mitk::MouseModeSwitcher::SetInteractionScheme( InteractionScheme scheme ) { switch ( scheme ) { case MITK : { ListenerList::iterator iter; for ( iter=m_ListenersForPACS.begin(); iter!=m_ListenersForPACS.end(); iter++ ) { m_GlobalInteraction->RemoveListener( (*iter) ); } for ( iter=m_ListenersForMITK.begin(); iter!=m_ListenersForMITK.end(); iter++ ) { m_GlobalInteraction->AddListener( (*iter) ); } break; } // case MITK case PACS : { ListenerList::iterator iter; for ( iter=m_ListenersForMITK.begin(); iter!=m_ListenersForMITK.end(); iter++ ) { m_GlobalInteraction->RemoveListener( (*iter) ); } for ( iter=m_ListenersForPACS.begin(); iter!=m_ListenersForPACS.end(); iter++ ) { m_GlobalInteraction->AddListener( (*iter) ); } this->SelectMouseMode( MousePointer ); break; } // case PACS } // switch m_ActiveInteractionScheme = scheme; } void mitk::MouseModeSwitcher::SelectMouseMode( MouseMode mode ) { if ( m_ActiveInteractionScheme != PACS ) return; switch ( mode ) { case MousePointer : { m_GlobalInteraction->RemoveListener( m_LeftMouseButtonHandler ); break; } // case 0 case Scroll : { m_GlobalInteraction->RemoveListener( m_LeftMouseButtonHandler ); mitk::DisplayVectorInteractorScroll::Pointer scrollInteractor = mitk::DisplayVectorInteractorScroll::New( - "LeftClickScroll", new mitk::DisplayInteractor() ); + "Scroll", new mitk::DisplayInteractor() ); m_LeftMouseButtonHandler = scrollInteractor; m_GlobalInteraction->AddListener( m_LeftMouseButtonHandler ); break; } // case 1 case LevelWindow : { m_GlobalInteraction->RemoveListener( m_LeftMouseButtonHandler ); mitk::DisplayVectorInteractorLevelWindow::Pointer lwInteractor = mitk::DisplayVectorInteractorLevelWindow::New( - "LeftClickLevelWindow" ); + "LevelWindow" ); m_LeftMouseButtonHandler = lwInteractor; m_GlobalInteraction->AddListener( m_LeftMouseButtonHandler ); break; } // case 2 case Zoom : { m_GlobalInteraction->RemoveListener( m_LeftMouseButtonHandler ); mitk::DisplayVectorInteractor::Pointer zoomInteractor = mitk::DisplayVectorInteractor::New( "Zoom", new mitk::DisplayInteractor() ); m_LeftMouseButtonHandler = zoomInteractor; m_GlobalInteraction->AddListener( m_LeftMouseButtonHandler ); break; } // case 3 case Pan : { m_GlobalInteraction->RemoveListener( m_LeftMouseButtonHandler ); mitk::DisplayVectorInteractor::Pointer panInteractor = mitk::DisplayVectorInteractor::New( "Pan", new mitk::DisplayInteractor() ); m_LeftMouseButtonHandler = panInteractor; m_GlobalInteraction->AddListener( m_LeftMouseButtonHandler ); break; } // case 4 } // switch (mode) m_ActiveMouseMode = mode; this->InvokeEvent( MouseModeChangedEvent() ); } mitk::MouseModeSwitcher::MouseMode mitk::MouseModeSwitcher::GetCurrentMouseMode() const { return m_ActiveMouseMode; } diff --git a/Core/Code/Testing/mitkImageTest.cpp b/Core/Code/Testing/mitkImageTest.cpp index 3fa1c680fa..c35048356e 100644 --- a/Core/Code/Testing/mitkImageTest.cpp +++ b/Core/Code/Testing/mitkImageTest.cpp @@ -1,341 +1,351 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // mitk includes #include #include #include #include "mitkItkImageFileReader.h" #include #include // itk includes #include #include // stl includes #include // vtk includes #include int mitkImageTest(int argc, char* argv[]) { MITK_TEST_BEGIN(mitkImageTest); //Create Image out of nowhere mitk::Image::Pointer imgMem = mitk::Image::New(); mitk::PixelType pt = mitk::MakeScalarPixelType(); unsigned int dim[]={100,100,20}; MITK_TEST_CONDITION_REQUIRED( imgMem.IsNotNull(), "An image was created. "); // Initialize image imgMem->Initialize( pt, 3, dim); MITK_TEST_CONDITION_REQUIRED( imgMem->IsInitialized(), "Image::IsInitialized() ?"); MITK_TEST_CONDITION_REQUIRED( imgMem->GetPixelType() == pt, "PixelType was set correctly."); int *p = (int*)imgMem->GetData(); MITK_TEST_CONDITION( p != NULL, "GetData() returned not-NULL pointer."); // FIXME: this is directly changing the image data // filling image const unsigned int size = dim[0]*dim[1]*dim[2]; for(unsigned int i=0; iGetData(); MITK_TEST_CONDITION( p2 != NULL, "GetData() returned not-NULL pointer."); bool isEqual = true; for(unsigned int i=0; iGetSliceData(dim[2]/2)->GetData(); MITK_TEST_CONDITION_REQUIRED( p2 != NULL, "Valid slice data returned"); unsigned int xy_size = dim[0]*dim[1]; unsigned int start_mid_slice = (dim[2]/2)*xy_size; isEqual = true; for(unsigned int i=0; i(); imgMem->Initialize( pType , 3, dim); MITK_TEST_CONDITION_REQUIRED(imgMem->GetDimension()== 3, "Testing initialization parameter dimension!"); MITK_TEST_CONDITION_REQUIRED(imgMem->GetPixelType() == pType, "Testing initialization parameter pixeltype!"); MITK_TEST_CONDITION_REQUIRED(imgMem->GetDimension(0) == dim[0] && imgMem->GetDimension(1)== dim[1] && imgMem->GetDimension(2)== dim[2], "Testing initialization of dimensions!"); MITK_TEST_CONDITION( imgMem->IsInitialized(), "Image is initialized."); // Setting volume again: imgMem->SetVolume(imgMem->GetData()); //----------------- // geometry information for image mitk::Point3D origin; mitk::Vector3D right, bottom; mitk::Vector3D spacing; mitk::FillVector3D(origin, 17.0, 19.92, 7.83); mitk::FillVector3D(right, 1.0, 2.0, 3.0); mitk::FillVector3D(bottom, 0.0, -3.0, 2.0); mitk::FillVector3D(spacing, 0.78, 0.91, 2.23); //InitializeStandardPlane(rightVector, downVector, spacing) mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); planegeometry->InitializeStandardPlane(100, 100, right, bottom, &spacing); planegeometry->SetOrigin(origin); // Testing Initialize(const mitk::PixelType& type, const mitk::Geometry3D& geometry, unsigned int slices) with PlaneGeometry and GetData(): "; imgMem->Initialize( mitk::MakePixelType(), *planegeometry); MITK_TEST_CONDITION_REQUIRED( imgMem->GetGeometry()->GetOrigin() == static_cast(planegeometry)->GetOrigin(), "Testing correct setting of geometry via initialize!"); p = (int*)imgMem->GetData(); MITK_TEST_CONDITION_REQUIRED( p!=NULL, "GetData() returned valid pointer."); // Testing Initialize(const mitk::PixelType& type, int sDim, const mitk::PlaneGeometry& geometry) and GetData(): "; imgMem->Initialize( mitk::MakePixelType() , 40, *planegeometry); p = (int*)imgMem->GetData(); MITK_TEST_CONDITION_REQUIRED( p!=NULL, "GetData() returned valid pointer."); //----------------- // testing origin information and methods MITK_TEST_CONDITION_REQUIRED( mitk::Equal(imgMem->GetGeometry()->GetOrigin(), origin), "Testing correctness of origin via GetGeometry()->GetOrigin(): "); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetOrigin(), origin), "Testing correctness of origin via GetTimeSlicedGeometry()->GetOrigin(): "); // Setting origin via SetOrigin(origin): "; mitk::FillVector3D(origin, 37.0, 17.92, 27.83); imgMem->SetOrigin(origin); // Test origin MITK_TEST_CONDITION_REQUIRED( mitk::Equal(imgMem->GetGeometry()->GetOrigin(), origin), "Testing correctness of changed origin via GetGeometry()->GetOrigin(): "); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetOrigin(), origin), "Testing correctness of changed origin via GetTimeSlicedGeometry()->GetOrigin(): "); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(imgMem->GetSlicedGeometry()->GetGeometry2D(0)->GetOrigin(), origin), "Testing correctness of changed origin via GetSlicedGeometry()->GetGeometry2D(0)->GetOrigin(): "); //----------------- // testing spacing information and methods MITK_TEST_CONDITION_REQUIRED(mitk::Equal(imgMem->GetGeometry()->GetSpacing(), spacing), "Testing correct spacing from Geometry3D!"); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetSpacing(), spacing), "Testing correctspacing from TimeSlicedGeometry!"); mitk::FillVector3D(spacing, 7.0, 0.92, 1.83); imgMem->SetSpacing(spacing); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(imgMem->GetGeometry()->GetSpacing(), spacing), "Testing correctness of changed spacing via GetGeometry()->GetSpacing(): "); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetSpacing(), spacing), "Testing correctness of changed spacing via GetTimeSlicedGeometry()->GetSpacing(): "); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(imgMem->GetSlicedGeometry()->GetGeometry2D(0)->GetSpacing(), spacing), "Testing correctness of changed spacing via GetSlicedGeometry()->GetGeometry2D(0)->GetSpacing(): "); mitk::Image::Pointer vecImg = mitk::Image::New(); vecImg->Initialize( imgMem->GetPixelType(), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/ ); vecImg->SetImportChannel(imgMem->GetData(), 0, mitk::Image::CopyMemory ); vecImg->SetImportChannel(imgMem->GetData(), 1, mitk::Image::CopyMemory ); MITK_TEST_CONDITION_REQUIRED(vecImg->GetChannelData(0)->GetData() != NULL && vecImg->GetChannelData(1)->GetData() != NULL, "Testing set and return of channel data!"); MITK_TEST_CONDITION_REQUIRED( vecImg->IsValidSlice(0,0,1) , ""); MITK_TEST_OUTPUT(<< " Testing whether CopyMemory worked"); MITK_TEST_CONDITION_REQUIRED(imgMem->GetData() != vecImg->GetData(), ""); MITK_TEST_OUTPUT(<< " Testing destruction after SetImportChannel"); vecImg = NULL; MITK_TEST_CONDITION_REQUIRED(vecImg.IsNull() , "testing destruction!"); //----------------- MITK_TEST_OUTPUT(<< "Testing initialization via vtkImageData"); MITK_TEST_OUTPUT(<< " Setting up vtkImageData"); vtkImageData* vtkimage = vtkImageData::New(); vtkimage->Initialize(); vtkimage->SetDimensions( 2, 3, 4); double vtkorigin[] = {-350,-358.203, -1363.5}; vtkimage->SetOrigin(vtkorigin); mitk::Point3D vtkoriginAsMitkPoint; mitk::vtk2itk(vtkorigin, vtkoriginAsMitkPoint); double vtkspacing[] = {1.367, 1.367, 2}; vtkimage->SetSpacing(vtkspacing); vtkimage->SetScalarType( VTK_SHORT ); vtkimage->AllocateScalars(); std::cout<<"[PASSED]"<Initialize(vtkimage); MITK_TEST_CONDITION_REQUIRED(mitkByVtkImage->IsInitialized(), ""); vtkimage->Delete(); MITK_TEST_OUTPUT(<< " Testing whether spacing has been correctly initialized from vtkImageData"); mitk::Vector3D spacing2 = mitkByVtkImage->GetGeometry()->GetSpacing(); mitk::Vector3D vtkspacingAsMitkVector; mitk::vtk2itk(vtkspacing, vtkspacingAsMitkVector); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(spacing2,vtkspacingAsMitkVector), ""); MITK_TEST_OUTPUT(<< " Testing whether GetSlicedGeometry(0)->GetOrigin() has been correctly initialized from vtkImageData"); mitk::Point3D origin2 = mitkByVtkImage->GetSlicedGeometry(0)->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2,vtkoriginAsMitkPoint), ""); MITK_TEST_OUTPUT(<< " Testing whether GetGeometry()->GetOrigin() has been correctly initialized from vtkImageData"); origin2 = mitkByVtkImage->GetGeometry()->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2,vtkoriginAsMitkPoint), ""); MITK_TEST_OUTPUT(<< " Testing whether GetTimeSlicedGeometry()->GetOrigin() has been correctly initialized from vtkImageData"); origin2 = mitkByVtkImage->GetTimeSlicedGeometry()->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2,vtkoriginAsMitkPoint), ""); // TODO test the following initializers on channel-incorporation // void mitk::Image::Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, unsigned int channels) // void mitk::Image::Initialize(const mitk::PixelType& type, int sDim, const mitk::Geometry2D& geometry2d, bool flipped, unsigned int channels, int tDim ) // void mitk::Image::Initialize(const mitk::Image* image) // void mitk::Image::Initialize(const mitkIpPicDescriptor* pic, int channels, int tDim, int sDim) //mitk::Image::Pointer vecImg = mitk::Image::New(); //vecImg->Initialize(PixelType(typeid(float), 6, itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/, false /*shiftBoundingBoxMinimumToZero*/ ); //vecImg->Initialize(PixelType(typeid(itk::Vector)), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/, false /*shiftBoundingBoxMinimumToZero*/ ); // testing access by index coordinates and by world coordinates MITK_TEST_CONDITION_REQUIRED(argc == 2, "Check if test image is accessible!"); const std::string filename = std::string(argv[1]); mitk::ItkImageFileReader::Pointer imageReader = mitk::ItkImageFileReader::New(); try { imageReader->SetFileName(filename); imageReader->Update(); } catch(...) { MITK_TEST_FAILED_MSG(<< "Could not read file for testing: " << filename); return 0; } mitk::Image::Pointer image = imageReader->GetOutput(); // generate a random point in world coordinates mitk::Point3D xMax, yMax, zMax, xMaxIndex, yMaxIndex, zMaxIndex; xMaxIndex.Fill(0.0f); yMaxIndex.Fill(0.0f); zMaxIndex.Fill(0.0f); xMaxIndex[0] = image->GetLargestPossibleRegion().GetSize()[0]; yMaxIndex[1] = image->GetLargestPossibleRegion().GetSize()[1]; zMaxIndex[2] = image->GetLargestPossibleRegion().GetSize()[2]; image->GetGeometry()->IndexToWorld(xMaxIndex, xMax); image->GetGeometry()->IndexToWorld(yMaxIndex, yMax); image->GetGeometry()->IndexToWorld(zMaxIndex, zMax); MITK_INFO << "Origin " << image->GetGeometry()->GetOrigin()[0] << " "<< image->GetGeometry()->GetOrigin()[1] << " "<< image->GetGeometry()->GetOrigin()[2] << ""; MITK_INFO << "MaxExtend " << xMax[0] << " "<< yMax[1] << " "<< zMax[2] << ""; mitk::Point3D point; itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer randomGenerator = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); randomGenerator->Initialize( std::rand() ); // initialize with random value, to get sensible random points for the image point[0] = randomGenerator->GetUniformVariate( image->GetGeometry()->GetOrigin()[0], xMax[0]); point[1] = randomGenerator->GetUniformVariate( image->GetGeometry()->GetOrigin()[1], yMax[1]); point[2] = randomGenerator->GetUniformVariate( image->GetGeometry()->GetOrigin()[2], zMax[2]); MITK_INFO << "RandomPoint " << point[0] << " "<< point[1] << " "<< point[2] << ""; // test values and max/min mitk::ScalarType imageMin = image->GetStatistics()->GetScalarValueMin(); mitk::ScalarType imageMax = image->GetStatistics()->GetScalarValueMax(); mitk::ScalarType value = image->GetPixelValueByWorldCoordinate(point); MITK_INFO << imageMin << " "<< imageMax << " "<< value << ""; MITK_TEST_CONDITION( (value >= imageMin && value <= imageMax), "Value returned is between max/min"); + // test accessing PixelValue with coordinate leading to a negative index + const mitk::Point3D geom_origin = image->GetGeometry()->GetOrigin(); + const mitk::Point3D geom_center = image->GetGeometry()->GetCenter(); + const unsigned int timestep = 0; + + // shift position from origin outside of the image ( in the opposite direction to [center-origin] vector which points in the inside) + mitk::Point3D position = geom_origin + (geom_origin - geom_center); + MITK_TEST_CONDITION_REQUIRED( image->GetPixelValueByWorldCoordinate(position, timestep) == 0, "Test access to the outside of the image") + + // testing the clone method of mitk::Image mitk::Image::Pointer cloneImage = image->Clone(); MITK_TEST_CONDITION_REQUIRED(cloneImage->GetDimension() == image->GetDimension(), "Clone (testing dimension)"); MITK_TEST_CONDITION_REQUIRED(cloneImage->GetPixelType() == image->GetPixelType(), "Clone (testing pixel type)"); // After cloning an image the geometry of both images should be equal too MITK_TEST_CONDITION_REQUIRED(cloneImage->GetGeometry()->GetOrigin() == image->GetGeometry()->GetOrigin(), "Clone (testing origin)"); MITK_TEST_CONDITION_REQUIRED(cloneImage->GetGeometry()->GetSpacing() == image->GetGeometry()->GetSpacing(), "Clone (testing spacing)"); MITK_TEST_CONDITION_REQUIRED(mitk::MatrixEqualElementWise(cloneImage->GetGeometry()->GetIndexToWorldTransform()->GetMatrix(), image->GetGeometry()->GetIndexToWorldTransform()->GetMatrix()), "Clone (testing transformation matrix)"); for (unsigned int i = 0u; i < cloneImage->GetDimension(); ++i) { MITK_TEST_CONDITION_REQUIRED(cloneImage->GetDimension(i) == image->GetDimension(i), "Clone (testing dimension " << i << ")"); } //access via itk if(image->GetDimension()> 3) // CastToItk only works with 3d images so we need to check for 4d images { mitk::ImageTimeSelector::Pointer selector = mitk::ImageTimeSelector::New(); selector->SetTimeNr(0); selector->SetInput(image); selector->Update(); image = selector->GetOutput(); } if(image->GetDimension()==3) { typedef itk::Image ItkFloatImage3D; ItkFloatImage3D::Pointer itkimage; mitk::CastToItkImage(image, itkimage); MITK_TEST_CONDITION_REQUIRED(itkimage.IsNotNull(), "Test conversion to itk::Image!"); mitk::Point3D itkPhysicalPoint; image->GetGeometry()->WorldToItkPhysicalPoint(point, itkPhysicalPoint); MITK_INFO << "ITKPoint " << itkPhysicalPoint[0] << " "<< itkPhysicalPoint[1] << " "<< itkPhysicalPoint[2] << ""; mitk::Point3D backTransformedPoint; image->GetGeometry()->ItkPhysicalPointToWorld(itkPhysicalPoint, backTransformedPoint); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(point,backTransformedPoint), "Testing world->itk-physical->world consistency"); itk::Index<3> idx; bool status = itkimage->TransformPhysicalPointToIndex(itkPhysicalPoint, idx); MITK_INFO << "ITK Index " << idx[0] << " "<< idx[1] << " "<< idx[2] << ""; if(status) { float valByItk = itkimage->GetPixel(idx); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(valByItk, value), "Compare value of pixel returned by mitk in comparison to itk"); } else { MITK_WARN<< "Index is out buffered region!"; } } else { MITK_INFO << "Image does not contain three dimensions, some test cases are skipped!"; } // clone generated 3D image with one slice in z direction (cf. bug 11058) unsigned int* threeDdim = new unsigned int[3]; threeDdim[0] = 100; threeDdim[1] = 200; threeDdim[2] = 1; mitk::Image::Pointer threeDImage = mitk::Image::New(); threeDImage->Initialize(mitk::MakeScalarPixelType(), 3, threeDdim); mitk::Image::Pointer cloneThreeDImage = threeDImage->Clone(); // check that the clone image has the same dimensionality as the source image MITK_TEST_CONDITION_REQUIRED( cloneThreeDImage->GetDimension() == 3, "Testing if the clone image initializes with 3D!"); MITK_TEST_END(); } diff --git a/Documentation/Doxygen/DeveloperManual/SupportedPlatforms.md b/Documentation/Doxygen/DeveloperManual/SupportedPlatforms.md index 2c0669b367..3a59b5239e 100644 --- a/Documentation/Doxygen/DeveloperManual/SupportedPlatforms.md +++ b/Documentation/Doxygen/DeveloperManual/SupportedPlatforms.md @@ -1,51 +1,51 @@ Supported Platforms {#SupportedPlatformsPage} =================== MITK is a cross-platform framework and is available for the following platforms: - Windows - Linux/X11 - Mac OS X Supported Platforms Details --------------------------- The MITK team provides support for the most frequently used platforms and continuously runs testing procedures to ensure compatibility. Due to the large amount of possible combinations of operating systems and compiler versions, we divide platform support into two test categories (Tier 1 and Tier 2). Although MITK may be built on a range of platform-compiler combinations, only a subset of these are actively support by the MITK development team. Tier 1 Platforms ---------------- All Tier 1 platforms are continuously tested by our unit test suite and other internal testing procedures. Errors or bugs discovered in these platforms are prioritized and corrected as soon as possible. | Platform | Compilers | ----------------------------------- | ----------------------------- | Ubuntu Linux 11.04 (64-bit) | As provided by Ubuntu | Microsoft Windows 7 (32 and 64-bit) | MSVC 2008 SP1 | Apple Mac OS X 10.7 "Lion" | LLVM-GCC as provided by Apple Tier 2 Platforms ---------------- Tier 2 platforms may or may not be tested on a regular basis. Some Tier 2 platforms are used by individual members of the MITK development team on a daily basis and some only receive occasional testing. While we strive to support these platforms, MITK users should note that errors may be present in released versions as well as in the current master branch. | Platform | Compilers | ---------------------------------- | ----------------------------- -| Ubuntu Linux 11.10 (64-bit) | As provided by Ubuntu -| Microsoft Windows 7 (32-bit) | MSVC 2010 +| Ubuntu Linux 11.04 (32-bit) | As provided by Ubuntu +| Microsoft Windows XP (32-bit) | MSVC 2008 SP1 | Apple Mac OS X 10.6 "Snow Leopard" | LLVM-GCC as provided by Apple All platforms not listed above are not officially supported by the MITK team. However, we will happily accept contributions to improve support for other platforms. diff --git a/Modules/QmitkExt/QmitkAdaptiveRegionGrowingWidget.cpp b/Modules/QmitkExt/QmitkAdaptiveRegionGrowingWidget.cpp index 9e93c0a7df..19a39cc1d2 100644 --- a/Modules/QmitkExt/QmitkAdaptiveRegionGrowingWidget.cpp +++ b/Modules/QmitkExt/QmitkAdaptiveRegionGrowingWidget.cpp @@ -1,806 +1,837 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkAdaptiveRegionGrowingWidget.h" #include "QmitkStdMultiWidget.h" #include #include "mitkNodePredicateDataType.h" #include "mitkGlobalInteraction.h" #include "mitkPointSetInteractor.h" #include "mitkProperties.h" #include "mitkITKImageImport.h" #include "mitkImageAccessByItk.h" #include "mitkTransferFunctionProperty.h" #include "mitkImageTimeSelector.h" +#include "mitkImageStatisticsHolder.h" + #include #include #include QmitkAdaptiveRegionGrowingWidget::QmitkAdaptiveRegionGrowingWidget(QWidget * parent) : QWidget(parent), m_MultiWidget(NULL), m_UseVolumeRendering(false), m_UpdateSuggestedThreshold(true), m_SuggestedThValue(0.0) { m_Controls.setupUi(this); m_NAMEFORSEEDPOINT = "Seed Point"; this->CreateConnections(); this->SetDataNodeNames("labeledRGSegmentation","RGResult","RGFeedbackSurface","RGSeedpoint"); } QmitkAdaptiveRegionGrowingWidget::~QmitkAdaptiveRegionGrowingWidget() { //Removing the observer of the PointSet node mitk::DataNode* node = m_DataStorage->GetNamedNode(m_NAMEFORSEEDPOINT); if (node != NULL) { this->DeactivateSeedPointMode(); dynamic_cast(node->GetData())->RemoveObserver(m_PointSetAddObserverTag); } + + this->RemoveHelperNodes(); + +} + +void QmitkAdaptiveRegionGrowingWidget::RemoveHelperNodes() +{ + mitk::DataNode::Pointer seedNode = m_DataStorage->GetNamedNode(m_NAMEFORSEEDPOINT); + if( seedNode.IsNotNull() ) + { + m_DataStorage->Remove(seedNode); + } + + mitk::DataNode::Pointer imageNode = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); + if( imageNode.IsNotNull() ) + { + m_DataStorage->Remove(imageNode); + } } void QmitkAdaptiveRegionGrowingWidget::CreateConnections() { //Connecting GUI components connect( (QObject*) (m_Controls.m_pbDefineSeedPoint), SIGNAL( toggled(bool) ), this, SLOT( SetSeedPointToggled(bool)) ); connect( (QObject*) (m_Controls.m_pbRunSegmentation), SIGNAL(clicked()), this, SLOT(RunSegmentation())); connect( (QObject*) (m_Controls.m_Slider), SIGNAL(valueChanged(int)), this, SLOT(ChangeLevelWindow(int)) ); connect( (QObject*) (m_Controls.m_DecreaseTH), SIGNAL(clicked()), this, SLOT(DecreaseSlider())); connect( (QObject*) (m_Controls.m_IncreaseTH), SIGNAL(clicked()), this,SLOT(IncreaseSlider())); connect( (QObject*) (m_Controls.m_pbConfirmSegementation), SIGNAL(clicked()), this, SLOT(ConfirmSegmentation())); connect( (QObject*) (m_Controls.m_cbVolumeRendering), SIGNAL(toggled(bool)), this, SLOT(UseVolumeRendering(bool) )); connect( m_Controls.m_LowerThresholdSpinBox, SIGNAL(valueChanged(double)), this, SLOT(SetLowerThresholdValue(double))); connect( m_Controls.m_UpperThresholdSpinBox, SIGNAL(valueChanged(double)), this, SLOT(SetUpperThresholdValue(double))); } void QmitkAdaptiveRegionGrowingWidget::SetDataNodeNames(std::string labledSegmentation, std::string binaryImage, std::string surface, std::string seedPoint) { m_NAMEFORLABLEDSEGMENTATIONIMAGE = labledSegmentation; m_NAMEFORBINARYIMAGE = binaryImage; m_NAMEFORSURFACE = surface; m_NAMEFORSEEDPOINT = seedPoint; } void QmitkAdaptiveRegionGrowingWidget::SetDataStorage(mitk::DataStorage* dataStorage) { m_DataStorage = dataStorage; } void QmitkAdaptiveRegionGrowingWidget::SetMultiWidget(QmitkStdMultiWidget* multiWidget) { m_MultiWidget = multiWidget; } void QmitkAdaptiveRegionGrowingWidget::SetInputImageNode(mitk::DataNode* node) { m_InputImageNode = node; } void QmitkAdaptiveRegionGrowingWidget::SetSeedPointToggled(bool toggled) { if (m_InputImageNode.IsNull()) { if (m_Controls.m_pbDefineSeedPoint->isChecked()) { QMessageBox::information( NULL, "Adaptive Region Growing functionality", "Please specify the image in Datamanager!"); m_Controls.m_pbDefineSeedPoint->toggle(); } return; } //check that a pointset node with the given name exists in data storage mitk::DataNode* node = m_DataStorage->GetNamedNode(m_NAMEFORSEEDPOINT); if (node == NULL) //no pointSet present { // new node and data item mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); pointSetNode->GetPropertyList()->SetProperty("name", mitk::StringProperty::New(m_NAMEFORSEEDPOINT)); pointSetNode->GetPropertyList()->SetProperty("helper object", mitk::BoolProperty::New(true)); pointSetNode->GetPropertyList()->SetProperty("layer", mitk::IntProperty::New(2)); mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); pointSetNode->SetData(pointSet); //Watch for point added or modified itk::SimpleMemberCommand::Pointer pointAddedCommand = itk::SimpleMemberCommand::New(); pointAddedCommand->SetCallbackFunction(this, &QmitkAdaptiveRegionGrowingWidget::OnPointAdded); m_PointSetAddObserverTag = pointSet->AddObserver( mitk::PointSetAddEvent(), pointAddedCommand); //add to DataStorage m_DataStorage->Add(pointSetNode, m_InputImageNode); } mitk::NodePredicateDataType::Pointer imagePred = mitk::NodePredicateDataType::New("Image"); mitk::DataStorage::SetOfObjects::ConstPointer setOfImages = m_DataStorage->GetSubset(imagePred); //no image node found if (setOfImages->Size() < 1) { QMessageBox::information(NULL, "Segmentation functionality", "Please load an image before setting a seed point."); return; } else { //get PointSet node from DataStorage mitk::DataNode* node = m_DataStorage->GetNamedNode(m_NAMEFORSEEDPOINT); if (node == NULL) { QMessageBox::critical(NULL, "QmitkAdaptiveRegionGrowingWidget", "No seed point node found!"); return; } if (toggled == true) // button is down { this->ActivateSeedPointMode(); //add pointSet Interactor if there is none } else { this->DeactivateSeedPointMode(); //disable pointSet Interactor } //enable the Run Segmentation button once the set seed point button is pressed m_Controls.m_pbRunSegmentation->setEnabled(true); } } void QmitkAdaptiveRegionGrowingWidget::OnPointAdded() { mitk::DataNode* node = m_DataStorage->GetNamedNode(m_NAMEFORSEEDPOINT); if (node != NULL) //no pointSet present { mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); if (pointSet.IsNull()) { QMessageBox::critical(NULL, "QmitkAdaptiveRegionGrowingWidget", "PointSetNode does not contain a pointset"); return; } mitk::Image* image = dynamic_cast(m_InputImageNode->GetData()); mitk::Point3D seedPoint = pointSet->GetPointSet(m_MultiWidget->GetTimeNavigationController()->GetTime()->GetPos())->GetPoints()->ElementAt(0); m_SeedpointValue = image->GetPixelValueByWorldCoordinate(seedPoint); /* In this case the seedpoint is placed e.g. in the lung or bronchialtree * The lowerFactor sets the windowsize depending on the regiongrowing direction */ m_CurrentRGDirectionIsUpwards = true; if (m_SeedpointValue < -500) { m_CurrentRGDirectionIsUpwards = false; } m_SeedPointValueMean = 0; mitk::Index3D currentIndex, runningIndex; mitk::ScalarType pixelValues[125]; unsigned int pos (0); image->GetGeometry(0)->WorldToIndex(seedPoint, currentIndex); runningIndex = currentIndex; for(int i = runningIndex[0]-2; i <= runningIndex[0]+2; i++) { for(int j = runningIndex[1]-2; j <= runningIndex[1]+2; j++) { for(int k = runningIndex[2]-2; k <= runningIndex[2]+2; k++) { currentIndex[0] = i; currentIndex[1] = j; currentIndex[2] = k; if(image->GetGeometry()->IsIndexInside(currentIndex)) { pixelValues[pos] = image->GetPixelValueByIndex(currentIndex); pos++; } else { pixelValues[pos] = -10000000; pos++; } } } } //Now calculation mean of the pixelValues unsigned int numberOfValues(0); for (unsigned int i = 0; i < 125; i++) { if(pixelValues[i] > -10000000) { m_SeedPointValueMean += pixelValues[i]; numberOfValues++; } } m_SeedPointValueMean = m_SeedPointValueMean/numberOfValues; /* * Here the upper- and lower threshold is calculated: * The windowSize is 20% of the maximum range of the intensity values existing in the current image * If the RG direction is upwards the lower TH is meanSeedValue-0.15*windowSize and upper TH is meanSeedValue+0.85*windowsSize * if the RG direction is downwards the lower TH is meanSeedValue-0.85*windowSize and upper TH is meanSeedValue+0.15*windowsSize */ - mitk::ScalarType min = image->GetScalarValueMin(); - mitk::ScalarType max = image->GetScalarValueMax(); + mitk::ScalarType min = image->GetStatistics()->GetScalarValueMin(); + mitk::ScalarType max = image->GetStatistics()->GetScalarValueMax(); mitk::ScalarType windowSize = max - min; windowSize = 0.15*windowSize; if (m_CurrentRGDirectionIsUpwards) { m_LOWERTHRESHOLD = m_SeedPointValueMean; if (m_SeedpointValue < m_SeedPointValueMean) m_LOWERTHRESHOLD = m_SeedpointValue; m_UPPERTHRESHOLD = m_SeedpointValue + windowSize; } else { m_UPPERTHRESHOLD = m_SeedPointValueMean; if (m_SeedpointValue > m_SeedPointValueMean) m_UPPERTHRESHOLD = m_SeedpointValue; m_LOWERTHRESHOLD = m_SeedpointValue - windowSize; } this->m_Controls.m_LowerThresholdSpinBox->setValue(m_LOWERTHRESHOLD); this->m_Controls.m_UpperThresholdSpinBox->setValue(m_UPPERTHRESHOLD); } } void QmitkAdaptiveRegionGrowingWidget::RunSegmentation() { if (m_InputImageNode.IsNull()) { QMessageBox::information( NULL, "Adaptive Region Growing functionality", "Please specify the image in Datamanager!"); return; } //release the "define seed point"-button if it is still pressed if (m_Controls.m_pbDefineSeedPoint->isChecked()) m_Controls.m_pbDefineSeedPoint->toggle(); mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode(m_NAMEFORSEEDPOINT); if (node.IsNull()) { QMessageBox::information( NULL, "Adaptive Region Growing functionality", "Please insert a seed point inside the image.\n\nFirst press the \"Define Seed Point\" button,\nthen click left mouse button inside the image."); return; } //safety if no pointSet or pointSet empty mitk::PointSet::Pointer seedPointSet = dynamic_cast (node->GetData()); if (seedPointSet.IsNull()) { m_Controls.m_pbRunSegmentation->setEnabled(true); QMessageBox::information( NULL, "Adaptive Region Growing functionality", "The seed point is empty! Please choose a new seed point."); return; } if (!(seedPointSet->GetSize(m_MultiWidget->GetTimeNavigationController()->GetTime()->GetPos()) > 0)) { m_Controls.m_pbRunSegmentation->setEnabled(true); m_Controls.m_pbDefineSeedPoint->setHidden(false); QMessageBox::information( NULL, "Adaptive Region Growing functionality", "The seed point is empty! Please choose a new seed point."); return; } int timeStep = m_MultiWidget->GetTimeNavigationController()->GetTime()->GetPos(); mitk::PointSet::PointType seedPoint = seedPointSet->GetPointSet(timeStep)->GetPoints()->Begin().Value(); mitk::Image::Pointer orgImage = dynamic_cast (m_InputImageNode->GetData()); if (orgImage.IsNotNull()) { if (orgImage->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(orgImage); timeSelector->SetTimeNr( timeStep ); timeSelector->UpdateLargestPossibleRegion(); mitk::Image* timedImage = timeSelector->GetOutput(); AccessByItk_2( timedImage , StartRegionGrowing, timedImage->GetGeometry(), seedPoint); } else if (orgImage->GetDimension() == 3) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); //set the cursor to waiting AccessByItk_2(orgImage, StartRegionGrowing, orgImage->GetGeometry(), seedPoint); QApplication::restoreOverrideCursor();//reset cursor } else { QMessageBox::information( NULL, "Adaptive Region Growing functionality", "Only images of dimension 3 or 4 can be processed!"); return; } } } template void QmitkAdaptiveRegionGrowingWidget::StartRegionGrowing(itk::Image* itkImage, mitk::Geometry3D* imageGeometry, mitk::PointSet::PointType seedPoint) { typedef itk::Image InputImageType; typedef typename InputImageType::IndexType IndexType; typedef itk::ConnectedAdaptiveThresholdImageFilter RegionGrowingFilterType; typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New(); typedef itk::MinimumMaximumImageCalculator MinMaxValueFilterType; if ( !imageGeometry->IsInside(seedPoint) ) { QApplication::restoreOverrideCursor();//reset cursor to be able to click ok with the regular mouse cursor QMessageBox::information( NULL, "Segmentation functionality", "The seed point is outside of the image! Please choose a position inside the image!"); return; } IndexType seedIndex; imageGeometry->WorldToIndex( seedPoint, seedIndex);// convert world coordinates to image indices if (m_SeedpointValue>m_UPPERTHRESHOLD || m_SeedpointValueSetGrowingDirectionIsUpwards( m_CurrentRGDirectionIsUpwards ); regionGrower->SetInput( itkImage ); regionGrower->AddSeed( seedIndex ); //In some cases we have to subtract 1 for the lower threshold and add 1 to the upper. //Otherwise no region growing is done. Maybe a bug in the ConnectiveAdaptiveThresholdFilter regionGrower->SetLower( m_LOWERTHRESHOLD-1 ); regionGrower->SetUpper( m_UPPERTHRESHOLD+1); try { regionGrower->Update(); } catch(itk::ExceptionObject &exc) { QMessageBox errorInfo; errorInfo.setWindowTitle("Adaptive RG Segmentation Functionality"); errorInfo.setIcon(QMessageBox::Critical); errorInfo.setText("An error occurred during region growing!"); errorInfo.setDetailedText(exc.what()); errorInfo.exec(); return; // can't work } catch( ... ) { QMessageBox::critical( NULL, "Adaptive RG Segmentation Functionality", "An error occurred during region growing!"); return; } this->m_SeedpointValue = regionGrower->GetSeedpointValue(); //initialize slider if(m_CurrentRGDirectionIsUpwards) { this->m_Controls.m_Slider->setMinimum(m_LOWERTHRESHOLD); this->m_Controls.m_Slider->setMaximum(m_UPPERTHRESHOLD); } else { m_Controls.m_Slider->setMinimum(m_LOWERTHRESHOLD); m_Controls.m_Slider->setMaximum(m_UPPERTHRESHOLD); } this->m_SliderInitialized = true; this->m_DetectedLeakagePoint = regionGrower->GetLeakagePoint(); mitk::Image::Pointer resultImage = mitk::ImportItkImage( regionGrower->GetOutput() ); //create new node and then delete the old one if there is one mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData( resultImage ); // set some properties newNode->SetProperty("name", mitk::StringProperty::New(m_NAMEFORLABLEDSEGMENTATIONIMAGE)); newNode->SetProperty("helper object", mitk::BoolProperty::New(true)); newNode->SetProperty("color", mitk::ColorProperty::New(1.0,0.0,0.0)); newNode->SetProperty("layer", mitk::IntProperty::New(1)); newNode->SetProperty("opacity", mitk::FloatProperty::New(0.7)); //delete the old image, if there was one: mitk::DataNode::Pointer binaryNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE); m_DataStorage->Remove(binaryNode); // now add result to data tree m_DataStorage->Add( newNode, m_InputImageNode ); this->InitializeLevelWindow(); if(m_UseVolumeRendering) this->EnableVolumeRendering(true); m_UpdateSuggestedThreshold = true;// reset first stored threshold value //Setting progress to finished mitk::ProgressBar::GetInstance()->Progress(357); } void QmitkAdaptiveRegionGrowingWidget::InitializeLevelWindow() { //get the preview from the datatree mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); mitk::LevelWindow tempLevelWindow; newNode->GetLevelWindow(tempLevelWindow, NULL, "levelwindow"); mitk::ScalarType* level = new mitk::ScalarType(0.0); mitk::ScalarType* window = new mitk::ScalarType(1.0); int upper; if (m_CurrentRGDirectionIsUpwards) { upper = m_UPPERTHRESHOLD - m_SeedpointValue; } else { upper = m_SeedpointValue - m_LOWERTHRESHOLD; } tempLevelWindow.SetRangeMinMax(mitk::ScalarType(0), mitk::ScalarType(upper)); //get the suggested threshold from the detected leakage-point and adjust the slider if (m_CurrentRGDirectionIsUpwards) { this->m_Controls.m_Slider->setValue(this->m_SeedpointValue + this->m_DetectedLeakagePoint -1); *level = m_UPPERTHRESHOLD - (this->m_SeedpointValue + this->m_DetectedLeakagePoint -1) + 0.5; } else { this->m_Controls.m_Slider->setValue(this->m_SeedpointValue - this->m_DetectedLeakagePoint +1); *level = (this->m_SeedpointValue + this->m_DetectedLeakagePoint +1) - m_LOWERTHRESHOLD + 0.5; } tempLevelWindow.SetLevelWindow(*level, *window); newNode->SetLevelWindow(tempLevelWindow, NULL, "levelwindow"); //update the widgets mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_SliderInitialized = true; //inquiry need to fix bug#1828 static int lastSliderPosition = 0; if ((this->m_SeedpointValue + this->m_DetectedLeakagePoint - 1) == lastSliderPosition) { this->ChangeLevelWindow(lastSliderPosition); } lastSliderPosition = this->m_SeedpointValue + this->m_DetectedLeakagePoint-1; this->m_MultiWidget->levelWindowWidget->GetManager()->SetAutoTopMostImage(false); this->m_MultiWidget->levelWindowWidget->GetManager()->SetLevelWindowProperty(static_cast(newNode->GetProperty("levelwindow"))); if (m_UseVolumeRendering) this->UpdateVolumeRenderingThreshold((int) (*level + 0.5));//lower threshold for labeled image } void QmitkAdaptiveRegionGrowingWidget::ChangeLevelWindow(int newValue) { if (m_SliderInitialized) { //do nothing, if no preview exists mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); if (newNode.IsNull()) return; mitk::LevelWindow tempLevelWindow; newNode->GetLevelWindow(tempLevelWindow, NULL, "levelwindow"); //get the levelWindow associated with the preview mitk::ScalarType level;// = this->m_UPPERTHRESHOLD - newValue + 0.5; mitk::ScalarType* window = new mitk::ScalarType(1); //adjust the levelwindow according to the position of the slider (newvalue) if (m_CurrentRGDirectionIsUpwards) { level = m_UPPERTHRESHOLD - newValue + 0.5; tempLevelWindow.SetLevelWindow(level, *window); } else { level = newValue - m_LOWERTHRESHOLD +0.5; tempLevelWindow.SetLevelWindow(level, *window); } newNode->SetLevelWindow(tempLevelWindow, NULL, "levelwindow"); if (m_UseVolumeRendering) this->UpdateVolumeRenderingThreshold((int) (level - 0.5));//lower threshold for labeled image this->m_Controls.m_SliderValueLabel->setNum(newValue); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkAdaptiveRegionGrowingWidget::DecreaseSlider() { //moves the slider one step to the left, when the "-"-button is pressed if (this->m_Controls.m_Slider->value() != this->m_Controls.m_Slider->minimum()) { int newValue = this->m_Controls.m_Slider->value() - 1; this->ChangeLevelWindow(newValue); this->m_Controls.m_Slider->setValue(newValue); } } void QmitkAdaptiveRegionGrowingWidget::IncreaseSlider() { //moves the slider one step to the right, when the "+"-button is pressed if (this->m_Controls.m_Slider->value() != this->m_Controls.m_Slider->maximum()) { int newValue = this->m_Controls.m_Slider->value() + 1; this->ChangeLevelWindow(newValue); this->m_Controls.m_Slider->setValue(newValue); } } void QmitkAdaptiveRegionGrowingWidget::ConfirmSegmentation() { //get image node if(m_InputImageNode.IsNull()) { QMessageBox::critical( NULL, "Adaptive region growing functionality", "Please specify the image in Datamanager!"); return; } //get image data mitk::Image::Pointer orgImage = dynamic_cast (m_InputImageNode->GetData()); if(orgImage.IsNull()) { QMessageBox::critical( NULL, "Adaptive region growing functionality", "No Image found!"); return; } //get labeled segmentation mitk::Image::Pointer labeledSeg = (mitk::Image*)m_DataStorage->GetNamedObject(m_NAMEFORLABLEDSEGMENTATIONIMAGE); if(labeledSeg.IsNull()) { QMessageBox::critical( NULL, "Adaptive region growing functionality", "No Segmentation Preview found!"); return; } mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); if (newNode.IsNull()) return; mitk::Image* img = dynamic_cast(newNode->GetData()); AccessByItk(img, ITKThresholding); + // disable volume rendering preview after the segmentation node was created + this->EnableVolumeRendering(false); + m_Controls.m_cbVolumeRendering->setChecked(false); } template void QmitkAdaptiveRegionGrowingWidget::ITKThresholding(itk::Image* itkImage) { typedef itk::Image InputImageType; typedef itk::Image SegmentationType; typedef itk::BinaryThresholdImageFilter ThresholdFilterType; typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New(); filter->SetInput(itkImage); filter->SetInsideValue(1); filter->SetOutsideValue(0); mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); if (newNode.IsNull()) return; mitk::LevelWindow tempLevelWindow; newNode->GetLevelWindow(tempLevelWindow, NULL, "levelwindow"); //get the levelWindow associated with the preview filter->SetUpperThreshold(tempLevelWindow.GetRangeMax()); if (m_CurrentRGDirectionIsUpwards) { filter->SetLowerThreshold(tempLevelWindow.GetLevel()+0.5); } else { filter->SetLowerThreshold(tempLevelWindow.GetLevel()+0.5); } filter->Update(); mitk::Image::Pointer new_image = mitk::Image::New(); mitk::CastToMitkImage(filter->GetOutput(), new_image); mitk::DataNode::Pointer segNode = mitk::DataNode::New(); segNode->SetData(new_image); segNode->SetName("RegionGrowing_Result"); segNode->SetBoolProperty("binary", mitk::BoolProperty::New(true)); //delete the old image, if there was one: mitk::DataNode::Pointer prevSegNode = m_DataStorage->GetNamedNode("RegionGrowing_Result"); m_DataStorage->Remove(prevSegNode); m_DataStorage->Add(segNode, m_InputImageNode); } void QmitkAdaptiveRegionGrowingWidget::EnableControls(bool enable) { //set the labels below the slider this->m_Controls.m_RSliderLabelLower->setText("Shrink"); this->m_Controls.m_RGSliderLaberUpper->setText("Expand"); this->m_Controls.m_RSliderLabelLower->setEnabled(enable); this->m_Controls.m_RGSliderLaberUpper->setEnabled(enable); this->m_Controls.m_pbRunSegmentation->setEnabled(enable); this->m_Controls.m_DecreaseTH->setEnabled(enable); this->m_Controls.m_IncreaseTH->setEnabled(enable); this->m_Controls.m_Slider->setEnabled(enable); this->m_Controls.m_pbConfirmSegementation->setEnabled(enable); } void QmitkAdaptiveRegionGrowingWidget::EnableVolumeRendering(bool enable) { mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); if(node.IsNull()) return; if(m_MultiWidget) m_MultiWidget->SetWidgetPlanesVisibility(!enable); if (enable) { node->SetBoolProperty("volumerendering", enable); node->SetBoolProperty("volumerendering.uselod", true); } else { node->SetBoolProperty("volumerendering", enable); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkAdaptiveRegionGrowingWidget::UpdateVolumeRenderingThreshold(int thValue) { mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); if (m_UpdateSuggestedThreshold) { m_SuggestedThValue = thValue; m_UpdateSuggestedThreshold = false; } // grayvalue->opacity { vtkPiecewiseFunction *f = tf->GetScalarOpacityFunction(); f->RemoveAllPoints(); f->AddPoint(0, 0); f->AddPoint(thValue+0.5, 0); f->AddPoint(thValue+1.5, 1); f->AddPoint(1000, 1); f->ClampingOn(); f->Modified(); } // grayvalue->color { float a = 255.0; vtkColorTransferFunction *ctf = tf->GetColorTransferFunction(); ctf->RemoveAllPoints(); //ctf->AddRGBPoint(-1000, 0.0, 0.0, 0.0); ctf->AddRGBPoint(m_SuggestedThValue+1, 203/a, 104/a, 102/a); ctf->AddRGBPoint(m_SuggestedThValue, 255/a, 0/a, 0/a); ctf->ClampingOn(); ctf->Modified(); } // GradientOpacityFunction { vtkPiecewiseFunction *gof = tf->GetGradientOpacityFunction(); gof->RemoveAllPoints(); gof->AddPoint(-10000, 1); gof->AddPoint(10000, 1); gof->ClampingOn(); gof->Modified(); } mitk::TransferFunctionProperty::Pointer tfp = mitk::TransferFunctionProperty::New(); tfp->SetValue(tf); node->SetProperty("TransferFunction", tfp); } void QmitkAdaptiveRegionGrowingWidget::UseVolumeRendering(bool on) { m_UseVolumeRendering = on; this->EnableVolumeRendering(on); } void QmitkAdaptiveRegionGrowingWidget::OnDefineThresholdBoundaries(bool status) { m_Controls.m_LowerThresholdSpinBox->setEnabled(status); m_Controls.m_UpperThresholdSpinBox->setEnabled(status); m_Controls.lb_LowerTh->setEnabled(status); m_Controls.lb_UpperTh->setEnabled(status); } void QmitkAdaptiveRegionGrowingWidget::SetLowerThresholdValue( double lowerThreshold ) { m_LOWERTHRESHOLD = lowerThreshold; } void QmitkAdaptiveRegionGrowingWidget::SetUpperThresholdValue( double upperThreshold) { m_UPPERTHRESHOLD = upperThreshold; } void QmitkAdaptiveRegionGrowingWidget::Deactivated() { this->DeactivateSeedPointMode(); + + // make the segmentation preview node invisible + mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); + if( node.IsNotNull() ) + { + node->SetVisibility(false); + } + + // disable volume rendering preview after the segmentation node was created + this->EnableVolumeRendering(false); + m_Controls.m_cbVolumeRendering->setChecked(false); } void QmitkAdaptiveRegionGrowingWidget::Activated() { - if(m_Controls.m_pbDefineSeedPoint->isChecked()) - { - this->ActivateSeedPointMode(); - } + } void QmitkAdaptiveRegionGrowingWidget::ActivateSeedPointMode() { mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode(m_NAMEFORSEEDPOINT); if(node.IsNotNull()) { //set the cursor to cross QApplication::setOverrideCursor(QCursor(Qt::CrossCursor)); mitk::PointSetInteractor::Pointer interactor = dynamic_cast (node->GetInteractor()); if (interactor.IsNull()) { //create a new interactor and add it to node interactor = mitk::PointSetInteractor::New("singlepointinteractorwithoutshiftclick", node, 1); } mitk::GlobalInteraction::GetInstance()->AddInteractor(interactor); } } void QmitkAdaptiveRegionGrowingWidget::DeactivateSeedPointMode() { //set the cursor to default again QApplication::restoreOverrideCursor(); mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode(m_NAMEFORSEEDPOINT); if(node.IsNotNull()) { mitk::PointSetInteractor::Pointer interactor = dynamic_cast (node->GetInteractor()); if (interactor.IsNotNull()) { mitk::GlobalInteraction::GetInstance()->RemoveInteractor(interactor); } } } diff --git a/Modules/QmitkExt/QmitkAdaptiveRegionGrowingWidget.h b/Modules/QmitkExt/QmitkAdaptiveRegionGrowingWidget.h index ebf6562256..f87d323aef 100644 --- a/Modules/QmitkExt/QmitkAdaptiveRegionGrowingWidget.h +++ b/Modules/QmitkExt/QmitkAdaptiveRegionGrowingWidget.h @@ -1,158 +1,160 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITK_AdaptiveRegionGrowingWidget_H #define QMITK_AdaptiveRegionGrowingWidget_H #include "mitkDataStorage.h" #include "itkImage.h" #include "mitkGeometry3D.h" #include "mitkPointSet.h" #include "qwidget.h" #include "ui_QmitkAdaptiveRegionGrowingWidgetControls.h" #include "QmitkExtExports.h" class QmitkStdMultiWidget; class DataNode; class QmitkAdaptiveRegionGrowingWidgetControls; /*! * * \brief QmitkAdaptiveRegionGrowingWidget * * Adaptive Region Growing View class of the segmentation. * */ class QmitkExt_EXPORT QmitkAdaptiveRegionGrowingWidget : public QWidget { Q_OBJECT public: typedef QmitkAdaptiveRegionGrowingWidget Self; /** * @brief Constructor. **/ QmitkAdaptiveRegionGrowingWidget(QWidget *parent=0); /** \brief Destructor. */ virtual ~QmitkAdaptiveRegionGrowingWidget(); /** \brief Method to create the connections for the component. This Method is obligatory even if no connections is needed*/ virtual void CreateConnections(); ///** \brief Method to set the default data storage.*/ virtual void SetDataStorage(mitk::DataStorage* dataStorage); void SetMultiWidget(QmitkStdMultiWidget* multiWidget); void SetDataNodeNames(std::string labledSegmentation, std::string binaryImage, /*std::string vesselTree,*/ std::string surface, std::string seedPoint); void EnableControls(bool enable); void SetInputImageNode(mitk::DataNode* node); void Deactivated(); void Activated(); /** * @brief The created GUI from the .ui-File. This Attribute is obligatory */ Ui::QmitkAdaptiveRegionGrowingWidgetControls m_Controls; protected slots: void SetSeedPointToggled(bool toggled); void RunSegmentation(); void ChangeLevelWindow(int newValue);//called, when the Level Window is changed via the slider in the ControlWidget //****called, when the slider-position is modified via the +/- buttons void IncreaseSlider(); void DecreaseSlider(); //*** void ConfirmSegmentation(); void UseVolumeRendering(bool on); void OnDefineThresholdBoundaries(bool); void SetLowerThresholdValue(double lowerThreshold); void SetUpperThresholdValue(double upperThreshold); protected: //Pointer to the main widget to be able to reach the renderer QmitkStdMultiWidget* m_MultiWidget; mitk::DataStorage* m_DataStorage; mitk::DataNode::Pointer m_InputImageNode; void DeactivateSeedPointMode(); void ActivateSeedPointMode(); void OnPointAdded(); private: std::string m_NAMEFORORGIMAGE; std::string m_NAMEFORSEEDPOINT; std::string m_NAMEFORLABLEDSEGMENTATIONIMAGE; std::string m_NAMEFORBINARYIMAGE; std::string m_NAMEFORSURFACE; mitk::ScalarType m_LOWERTHRESHOLD; //Hounsfield value mitk::ScalarType m_UPPERTHRESHOLD; //Hounsfield value mitk::ScalarType m_SeedPointValueMean; + void RemoveHelperNodes(); + int m_DetectedLeakagePoint; bool m_CurrentRGDirectionIsUpwards; // defines fixed threshold (true = LOWERTHRESHOLD fixed, false = UPPERTHRESHOLD fixed) int m_SeedpointValue; bool m_SliderInitialized; bool m_UseVolumeRendering; bool m_UpdateSuggestedThreshold; float m_SuggestedThValue; long m_PointSetAddObserverTag; template < typename TPixel, unsigned int VImageDimension > void StartRegionGrowing( itk::Image< TPixel, VImageDimension >* itkImage, mitk::Geometry3D* imageGeometry, mitk::PointSet::PointType seedPoint ); template < typename TPixel, unsigned int VImageDimension > void ITKThresholding( itk::Image< TPixel, VImageDimension >* inputImage ); void InitializeLevelWindow(); void EnableVolumeRendering(bool enable); void UpdateVolumeRenderingThreshold(int thValue); }; #endif diff --git a/Modules/Segmentation/Interactions/mitkPaintbrushTool.cpp b/Modules/Segmentation/Interactions/mitkPaintbrushTool.cpp index 3e59afea4e..ba15b2ad07 100644 --- a/Modules/Segmentation/Interactions/mitkPaintbrushTool.cpp +++ b/Modules/Segmentation/Interactions/mitkPaintbrushTool.cpp @@ -1,376 +1,379 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPaintbrushTool.h" #include "mitkToolManager.h" #include "mitkOverwriteSliceImageFilter.h" #include "mitkBaseRenderer.h" #include "mitkImageDataItem.h" #include "ipSegmentation.h" #include "mitkLevelWindowProperty.h" #define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) int mitk::PaintbrushTool::m_Size = 1; mitk::PaintbrushTool::PaintbrushTool(int paintingPixelValue) :FeedbackContourTool("PressMoveReleaseWithCTRLInversionAllMouseMoves"), m_PaintingPixelValue(paintingPixelValue), m_LastContourSize(0) // other than initial mitk::PaintbrushTool::m_Size (around l. 28) { m_MasterContour = Contour::New(); m_MasterContour->Initialize(); m_CurrentPlane = NULL; m_WorkingNode = DataNode::New(); m_WorkingNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( mitk::LevelWindow(0, 1) ) ); m_WorkingNode->SetProperty( "binary", mitk::BoolProperty::New(true) ); } mitk::PaintbrushTool::~PaintbrushTool() { } void mitk::PaintbrushTool::Activated() { Superclass::Activated(); FeedbackContourTool::SetFeedbackContourVisible(true); SizeChanged.Send(m_Size); } void mitk::PaintbrushTool::Deactivated() { FeedbackContourTool::SetFeedbackContourVisible(false); if (m_ToolManager->GetDataStorage()->Exists(m_WorkingNode)) m_ToolManager->GetDataStorage()->Remove(m_WorkingNode); Superclass::Deactivated(); m_WorkingSlice = NULL; m_CurrentPlane = NULL; } void mitk::PaintbrushTool::SetSize(int value) { m_Size = value; } void mitk::PaintbrushTool::UpdateContour(const StateEvent* stateEvent) { //MITK_INFO<<"Update..."; // examine stateEvent and create a contour that matches the pixel mask that we are going to draw const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return; // create a copy of this slice (at least match the pixel sizes/spacings), // then draw the desired mask on it and create a contour from it // Convert to ipMITKSegmentationTYPE (because getting pixels relys on that data type) itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer correctPixelTypeImage; CastToItkImage(m_WorkingSlice/*dynamic_cast(m_WorkingNode->GetData())*/, correctPixelTypeImage ); assert (correctPixelTypeImage.IsNotNull() ); itk::Image< ipMITKSegmentationTYPE, 2 >::DirectionType imageDirection; imageDirection.SetIdentity(); correctPixelTypeImage->SetDirection(imageDirection); Image::Pointer temporarySlice = Image::New(); CastToMitkImage( correctPixelTypeImage, temporarySlice ); //mitkIpPicDescriptor* stupidClone = mitkIpPicClone( temporarySlice->GetSliceData()->GetPicDescriptor() ); mitkIpPicDescriptor* stupidClone = mitkIpPicNew(); CastToIpPicDescriptor( temporarySlice->GetSliceData(), stupidClone ); unsigned int pixelWidth = m_Size + 1; unsigned int pixelHeight = m_Size + 1; if ( stupidClone->n[0] <= pixelWidth || stupidClone->n[1] <= pixelHeight ) { MITK_INFO << "Brush size is bigger than your working image. Reconsider this...\n" "(Or tell your progammer until (s)he fixes this message.)" << std::endl; mitkIpPicFree( stupidClone ); return; } unsigned int lineLength( stupidClone->n[0] ); unsigned int oneContourOffset(0); float circleCenterX = (float)m_Size / 2.0; float circleCenterY = (float)m_Size / 2.0; for (unsigned int x = 0; x <= pixelWidth; ++x) { for (unsigned int y = 0; y <= pixelHeight; ++y) { unsigned int offset = lineLength * y + x; ipMITKSegmentationTYPE* current = (ipMITKSegmentationTYPE*)stupidClone->data + offset; float pixelCenterX = x + 0.5; float pixelCenterY = y + 0.5; float xoff = pixelCenterX - circleCenterX; float yoff = pixelCenterY - circleCenterY; bool inside = xoff * xoff + yoff * yoff < (m_Size * m_Size) / 4.0; // no idea, if this would work for ellipses if (inside) { *current = 1; oneContourOffset = offset; } else { *current = 0; } } } int numberOfContourPoints( 0 ); int newBufferSize( 0 ); float* contourPoints = ipMITKSegmentationGetContour8N( stupidClone, oneContourOffset, numberOfContourPoints, newBufferSize ); // memory allocated with malloc if (!contourPoints) { mitkIpPicFree( stupidClone ); return; } // copy point from float* to mitk::Contour Contour::Pointer contourInImageIndexCoordinates = Contour::New(); contourInImageIndexCoordinates->Initialize(); Point3D newPoint; //ipMITKSegmentationGetContour8N returns all points, which causes vtk warnings, since the first and the last points are coincident. //leaving the last point out, the contour is still drawn correctly for (int index = 0; index < numberOfContourPoints-1; ++index) { newPoint[0] = contourPoints[ 2 * index + 0 ] - circleCenterX; // master contour should be centered around (0,0) newPoint[1] = contourPoints[ 2 * index + 1] - circleCenterY; newPoint[2] = 0.0; MITK_DEBUG << "Point [" << index << "] (" << newPoint[0] << ", " << newPoint[1] << ")" << std::endl; contourInImageIndexCoordinates->AddVertex( newPoint ); } free(contourPoints); m_MasterContour = contourInImageIndexCoordinates; // The PicDescriptor is only REFERENCING(!) the data, the temporarySlice takes care of deleting the data also the descriptor is pointing on // because they got allocated by the ImageDataItem, not the descriptor. stupidClone->data = NULL; mitkIpPicFree( stupidClone ); } /** Just show the contour, get one point as the central point and add surrounding points to the contour. */ bool mitk::PaintbrushTool::OnMousePressed (Action* action, const StateEvent* stateEvent) { return this->OnMouseMoved(action, stateEvent); } /** Insert the point to the feedback contour,finish to build the contour and at the same time the painting function */ bool mitk::PaintbrushTool::OnMouseMoved (Action* itkNotUsed(action), const StateEvent* stateEvent) { const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return false; CheckIfCurrentSliceHasChanged(positionEvent); if ( m_LastContourSize != m_Size ) { UpdateContour( stateEvent ); m_LastContourSize = m_Size; } bool leftMouseButtonPressed( stateEvent->GetId() == 530 || stateEvent->GetId() == 534 || stateEvent->GetId() == 1 || stateEvent->GetId() == 5 ); Point3D worldCoordinates = positionEvent->GetWorldPosition(); Point3D indexCoordinates; m_WorkingSlice->GetGeometry()->WorldToIndex( worldCoordinates, indexCoordinates ); MITK_DEBUG << "Mouse at W " << worldCoordinates << std::endl; MITK_DEBUG << "Mouse at I " << indexCoordinates << std::endl; // round to nearest voxel center (abort if this hasn't changed) if ( m_Size % 2 == 0 ) // even { indexCoordinates[0] = ROUND( indexCoordinates[0] /*+ 0.5*/) + 0.5; indexCoordinates[1] = ROUND( indexCoordinates[1] /*+ 0.5*/ ) + 0.5; } else // odd { indexCoordinates[0] = ROUND( indexCoordinates[0] ) ; indexCoordinates[1] = ROUND( indexCoordinates[1] ) ; } static Point3D lastPos; // uninitialized: if somebody finds out how this can be initialized in a one-liner, tell me if ( fabs(indexCoordinates[0] - lastPos[0]) > mitk::eps || fabs(indexCoordinates[1] - lastPos[1]) > mitk::eps || fabs(indexCoordinates[2] - lastPos[2]) > mitk::eps || leftMouseButtonPressed ) { lastPos = indexCoordinates; } else { MITK_DEBUG << "." << std::flush; return false; } MITK_DEBUG << "Mouse at C " << indexCoordinates; Contour::Pointer contour = Contour::New(); contour->Initialize(); for (unsigned int index = 0; index < m_MasterContour->GetNumberOfPoints(); ++index) { Point3D point = m_MasterContour->GetPoints()->ElementAt(index); point[0] += indexCoordinates[ 0 ]; point[1] += indexCoordinates[ 1 ]; contour->AddVertex( point ); } if (leftMouseButtonPressed) { FeedbackContourTool::FillContourInSlice( contour, m_WorkingSlice, m_PaintingPixelValue ); m_WorkingNode->SetData(m_WorkingSlice); m_WorkingNode->Modified(); } // visualize contour Contour::Pointer displayContour = Contour::New(); displayContour->Initialize(); //for (unsigned int index = 0; index < contour->GetNumberOfPoints(); ++index) //{ // Point3D point = contour->GetPoints()->ElementAt(index); // if ( m_Size % 2 == 0 ) // even // { // point[0] += 0.5; // point[1] += 0.5; // } // displayContour->AddVertex( point ); //} displayContour = FeedbackContourTool::BackProjectContourFrom2DSlice( m_WorkingSlice->GetGeometry(), /*displayContour*/contour ); SetFeedbackContour( *displayContour ); assert( positionEvent->GetSender()->GetRenderWindow() ); RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); return true; } bool mitk::PaintbrushTool::OnMouseReleased(Action* /*action*/, const StateEvent* stateEvent) { //When mouse is released write segmentationresult back into image const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return false; this->WriteBackSegmentationResult(positionEvent, m_WorkingSlice); -// FeedbackContourTool::SetFeedbackContourVisible(false); return true; } /** Called when the CTRL key is pressed. Will change the painting pixel value from 0 to 1 or from 1 to 0. */ bool mitk::PaintbrushTool::OnInvertLogic(Action* action, const StateEvent* stateEvent) { if (!FeedbackContourTool::OnInvertLogic(action, stateEvent)) return false; // Inversion only for 0 and 1 as painting values if (m_PaintingPixelValue == 1) { m_PaintingPixelValue = 0; FeedbackContourTool::SetFeedbackContourColor( 1.0, 0.0, 0.0 ); } else if (m_PaintingPixelValue == 0) { m_PaintingPixelValue = 1; FeedbackContourTool::SetFeedbackContourColorDefault(); } return true; } void mitk::PaintbrushTool::CheckIfCurrentSliceHasChanged(const PositionEvent *event) { const PlaneGeometry* planeGeometry( dynamic_cast (event->GetSender()->GetCurrentWorldGeometry2D() ) ); DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); if (!workingNode) return; Image::Pointer image = dynamic_cast(workingNode->GetData()); if ( !image || !planeGeometry ) return; if(m_CurrentPlane.IsNull()) { m_CurrentPlane = const_cast(planeGeometry); m_WorkingSlice = SegTool2D::GetAffectedImageSliceAs2DImage(event, image)->Clone(); m_WorkingNode->ReplaceProperty( "color", workingNode->GetProperty("color") ); m_WorkingNode->SetData(m_WorkingSlice); } else { bool isSameSlice (false); isSameSlice = mitk::MatrixEqualElementWise(planeGeometry->GetIndexToWorldTransform()->GetMatrix(),m_CurrentPlane->GetIndexToWorldTransform()->GetMatrix()); isSameSlice = mitk::Equal(planeGeometry->GetIndexToWorldTransform()->GetOffset(),m_CurrentPlane->GetIndexToWorldTransform()->GetOffset()); if (!isSameSlice) { m_ToolManager->GetDataStorage()->Remove(m_WorkingNode); m_CurrentPlane = NULL; m_WorkingSlice = NULL; m_WorkingNode = NULL; m_CurrentPlane = const_cast(planeGeometry); m_WorkingSlice = SegTool2D::GetAffectedImageSliceAs2DImage(event, image)->Clone(); m_WorkingNode = mitk::DataNode::New(); m_WorkingNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( mitk::LevelWindow(0, 1) ) ); m_WorkingNode->SetProperty( "binary", mitk::BoolProperty::New(true) ); m_WorkingNode->SetData(m_WorkingSlice); + + //So that the paintbrush contour vanished in the previous render window + RenderingManager::GetInstance()->RequestUpdateAll(); } } if(!m_ToolManager->GetDataStorage()->Exists(m_WorkingNode)) { m_WorkingNode->SetProperty( "outline binary", mitk::BoolProperty::New(true) ); m_WorkingNode->SetProperty( "color", workingNode->GetProperty("color") ); m_WorkingNode->SetProperty( "name", mitk::StringProperty::New("Paintbrush_Node") ); m_WorkingNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); m_WorkingNode->SetProperty( "opacity", mitk::FloatProperty::New(0.8) ); m_WorkingNode->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(false)); + m_WorkingNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); m_ToolManager->GetDataStorage()->Add(m_WorkingNode); } } diff --git a/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml b/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml index 6cc6005c05..f893b6b51b 100644 --- a/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml +++ b/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml @@ -1,3824 +1,3867 @@ - + + + + + + + + + + + + + - + - - - + + + - + - + - + - + - + - - - - + + + + - - - - + + + + - - - - - - + + + + + + - - - - - - - - + + + + + + + + - + - + - - - + + + - + - + - - - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - - - - - - + + + + + + - + - + - + - + - + diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/regiongrowing/QmitkRegionGrowingView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/regiongrowing/QmitkRegionGrowingView.cpp index a1280b58c7..01e2a48a34 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/regiongrowing/QmitkRegionGrowingView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/regiongrowing/QmitkRegionGrowingView.cpp @@ -1,87 +1,93 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkRegionGrowingView.h" #include "QmitkStdMultiWidget.h" const std::string QmitkRegionGrowingView::VIEW_ID = "org.mitk.views.regiongrowing"; QmitkRegionGrowingView::QmitkRegionGrowingView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) { } QmitkRegionGrowingView::~QmitkRegionGrowingView() { } void QmitkRegionGrowingView::Deactivated() { + m_Controls->m_AdaptiveRGWidget->Deactivated(); +} + +void QmitkRegionGrowingView::Activated() +{ + m_Controls->m_AdaptiveRGWidget->Activated(); } void QmitkRegionGrowingView::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::QmitkRegionGrowingViewControls; m_Controls->setupUi( parent ); m_Controls->m_AdaptiveRGWidget->SetDataStorage(this->GetDataStorage()); m_Controls->m_AdaptiveRGWidget->CreateConnections(); } } void QmitkRegionGrowingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; m_Controls->m_AdaptiveRGWidget->SetMultiWidget(&stdMultiWidget); } void QmitkRegionGrowingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkRegionGrowingView::OnSelectionChanged( std::vector nodes ) { // iterate all selected objects, adjust warning visibility for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_Controls->lblWarning->setVisible( false ); m_Controls->m_AdaptiveRGWidget->SetInputImageNode(node); return; } } m_Controls->lblWarning->setVisible( true ); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/regiongrowing/QmitkRegionGrowingView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/regiongrowing/QmitkRegionGrowingView.h index f67cbc22a2..2b99308f1a 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/regiongrowing/QmitkRegionGrowingView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/regiongrowing/QmitkRegionGrowingView.h @@ -1,81 +1,82 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkRegionGrowingView_h #define QmitkRegionGrowingView_h #include #include #include "ui_QmitkRegionGrowingViewControls.h" /*! \brief QmitkRegionGrowingView Functionality for demonstration of MITK basics. This functionality allows the user to set some seed points that are used for a simple region growing algorithm from ITK. \warning This is only for demonstration, it is NOT meant to be useful! \sa QmitkFunctionality \ingroup Functionalities */ class QmitkRegionGrowingView : public QmitkFunctionality { // 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: static const std::string VIEW_ID; QmitkRegionGrowingView(); virtual ~QmitkRegionGrowingView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void Deactivated(); + virtual void Activated(); protected slots: protected: /*! \brief ITK image processing function This function is templated like an ITK image. The MITK-Macro AccessByItk determines the actual pixel type and dimensionality of a given MITK image and calls this function for further processing (in our case region growing) */ template < typename TPixel, unsigned int VImageDimension > void ItkImageProcessing( itk::Image< TPixel, VImageDimension >* itkImage, mitk::Geometry3D* imageGeometry, mitk::DataNode* parent, int thresholdOffset, unsigned int t ); /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ); Ui::QmitkRegionGrowingViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; }; #endif // _QMITKREGIONGROWINGVIEW_H_INCLUDED