diff --git a/CMake/mitkFunctionGetLibrarySearchPaths.cmake b/CMake/mitkFunctionGetLibrarySearchPaths.cmake index faeb5e64ca..5b8e9e38b5 100644 --- a/CMake/mitkFunctionGetLibrarySearchPaths.cmake +++ b/CMake/mitkFunctionGetLibrarySearchPaths.cmake @@ -1,152 +1,160 @@ function(mitkFunctionGetLibrarySearchPaths search_path intermediate_dir) set(_dir_candidates "${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}" "${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}/plugins" "${MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY}" "${MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY}/plugins" ) if(MITK_EXTERNAL_PROJECT_PREFIX) list(APPEND _dir_candidates "${MITK_EXTERNAL_PROJECT_PREFIX}/bin" "${MITK_EXTERNAL_PROJECT_PREFIX}/lib" ) endif() # Determine the Qt5 library installation prefix set(_qmake_location ) if(MITK_USE_Qt5 AND TARGET ${Qt5Core_QMAKE_EXECUTABLE}) get_property(_qmake_location TARGET ${Qt5Core_QMAKE_EXECUTABLE} PROPERTY IMPORT_LOCATION) endif() if(_qmake_location) if(NOT _qt_install_libs) if(WIN32) execute_process(COMMAND ${_qmake_location} -query QT_INSTALL_BINS OUTPUT_VARIABLE _qt_install_libs OUTPUT_STRIP_TRAILING_WHITESPACE) else() execute_process(COMMAND ${_qmake_location} -query QT_INSTALL_LIBS OUTPUT_VARIABLE _qt_install_libs OUTPUT_STRIP_TRAILING_WHITESPACE) endif() file(TO_CMAKE_PATH "${_qt_install_libs}" _qt_install_libs) set(_qt_install_libs ${_qt_install_libs} CACHE INTERNAL "Qt library installation prefix" FORCE) endif() if(_qt_install_libs) list(APPEND _dir_candidates ${_qt_install_libs}) endif() elseif(MITK_USE_Qt5) message(WARNING "The qmake executable could not be found.") endif() get_property(_additional_paths GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) if(MITK_USE_HDF5) FIND_PACKAGE(HDF5 COMPONENTS C HL NO_MODULE REQUIRED shared) get_target_property(_location hdf5-shared LOCATION) get_filename_component(_location ${_location} PATH) list(APPEND _additional_paths ${_location}) # This is a work-around. The hdf5-config.cmake file is not robust enough # to be included several times via find_pakcage calls. set(HDF5_LIBRARIES ${HDF5_LIBRARIES} PARENT_SCOPE) endif() if(MITK_USE_Vigra) # we cannot use _find_package(Vigra) here because the vigra-config.cmake file # always includes the target-exports files without using an include guard. This # would lead to errors when another find_package(Vigra) call is processed. The # (bad) assumption here is that for the time being, only the Classification module # is using Vigra. if(UNIX) list(APPEND _additional_paths ${Vigra_DIR}/lib) else() list(APPEND _additional_paths ${Vigra_DIR}/bin) endif() endif() if(_additional_paths) list(APPEND _dir_candidates ${_additional_paths}) endif() # The code below is sub-optimal. It makes assumptions about # the structure of the build directories, pointed to by # the *_DIR variables. Instead, we should rely on package # specific "LIBRARY_DIRS" variables, if they exist. if(WIN32) list(APPEND _dir_candidates "${ITK_DIR}/bin") endif() if(MITK_USE_MatchPoint) if(WIN32) list(APPEND _dir_candidates "${MatchPoint_DIR}/bin") else() list(APPEND _dir_candidates "${MatchPoint_DIR}/lib") endif() endif() - if(OpenCV_DIR) + # If OpenCV is built within the MITK superbuild set the binary directory + # according to the lib path provided by OpenCV. + # In the case where an external OpenCV is provided use the binary directory + # of this OpenCV directory + if(MITK_USE_OpenCV) if(WIN32) - list(APPEND _dir_candidates "${OpenCV_LIB_PATH}/../bin") + if (EXISTS ${OpenCV_LIB_PATH}) + list(APPEND _dir_candidates "${OpenCV_LIB_PATH}/../bin") # OpenCV is built in superbuild + else() + list(APPEND _dir_candidates "${OpenCV_DIR}/bin") # External OpenCV build is used + endif() endif() endif() if(MITK_USE_Python) list(APPEND _dir_candidates "${CTK_DIR}/CMakeExternals/Install/bin") get_filename_component(_python_dir ${PYTHON_EXECUTABLE} DIRECTORY) list(APPEND _dir_candidates "${_python_dir}") endif() if(MITK_USE_TOF_PMDO3 OR MITK_USE_TOF_PMDCAMCUBE OR MITK_USE_TOF_PMDCAMBOARD) list(APPEND _dir_candidates "${MITK_PMD_SDK_DIR}/plugins" "${MITK_PMD_SDK_DIR}/bin") endif() if(MITK_USE_CTK) list(APPEND _dir_candidates "${CTK_LIBRARY_DIRS}") foreach(_ctk_library ${CTK_LIBRARIES}) if(${_ctk_library}_LIBRARY_DIRS) list(APPEND _dir_candidates "${${_ctk_library}_LIBRARY_DIRS}") endif() endforeach() endif() if(MITK_USE_BLUEBERRY) if(DEFINED CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY) if(IS_ABSOLUTE "${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}") list(APPEND _dir_candidates "${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}") else() list(APPEND _dir_candidates "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}") endif() endif() endif() if(MITK_LIBRARY_DIRS) list(APPEND _dir_candidates ${MITK_LIBRARY_DIRS}) endif() list(REMOVE_DUPLICATES _dir_candidates) set(_search_dirs ) foreach(_dir ${_dir_candidates}) if(EXISTS "${_dir}/${intermediate_dir}") list(APPEND _search_dirs "${_dir}/${intermediate_dir}") else() list(APPEND _search_dirs "${_dir}") endif() endforeach() # Special handling for "internal" search dirs. The intermediate directory # might not have been created yet, so we can't check for its existence. # Hence we just add it for Windows without checking. set(_internal_search_dirs "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/plugins") if(WIN32) foreach(_dir ${_internal_search_dirs}) set(_search_dirs "${_dir}/${intermediate_dir}" ${_search_dirs}) endforeach() else() set(_search_dirs ${_internal_search_dirs} ${_search_dirs}) endif() list(REMOVE_DUPLICATES _search_dirs) set(${search_path} ${_search_dirs} PARENT_SCOPE) endfunction() diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake index e5626453b7..dc12a0653a 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,37 +1,37 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) - set(revision_tag 4e3195a3) # first 8 characters of hash-tag + set(revision_tag 5ad3bb57) # first 8 characters of hash-tag # ^^^^^^^^ these are just to check correct length of hash part ExternalProject_Add(${proj} SOURCE_DIR ${proj} GIT_REPOSITORY https://phabricator.mitk.org/source/mitkdata.git GIT_TAG ${revision_tag} # URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/mitk-data_${revision_tag}.tar.gz UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${proj_DEPENDENCIES} ) set(MITK_DATA_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/CMakeExternals/SimpleITK.cmake b/CMakeExternals/SimpleITK.cmake index 1f6bff9370..87a11b0548 100644 --- a/CMakeExternals/SimpleITK.cmake +++ b/CMakeExternals/SimpleITK.cmake @@ -1,137 +1,139 @@ #----------------------------------------------------------------------------- # SimpleITK #----------------------------------------------------------------------------- if(MITK_USE_SimpleITK) # Sanity checks if(DEFINED SimpleITK_DIR AND NOT EXISTS ${SimpleITK_DIR}) message(FATAL_ERROR "SimpleITK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj SimpleITK) set(proj_DEPENDENCIES ITK GDCM SWIG) if(MITK_USE_OpenCV) list(APPEND proj_DEPENDENCIES OpenCV) endif() set(SimpleITK_DEPENDS ${proj}) if(NOT DEFINED SimpleITK_DIR) set(additional_cmake_args ) list(APPEND additional_cmake_args -DWRAP_CSHARP:BOOL=OFF -DWRAP_TCL:BOOL=OFF -DWRAP_LUA:BOOL=OFF -DWRAP_PYTHON:BOOL=OFF -DWRAP_JAVA:BOOL=OFF -DWRAP_RUBY:BOOL=OFF -DWRAP_R:BOOL=OFF ) if(MITK_USE_Python) list(APPEND additional_cmake_args -DWRAP_PYTHON:BOOL=ON -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} -DPYTHON_INCLUDE_DIR2:PATH=${PYTHON_INCLUDE_DIR2} -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY} ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() #TODO: Installer and testing works only with static libs on MAC set(_build_shared ON) if(APPLE) set(_build_shared OFF) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} #GIT_REPOSITORY https://github.com/SimpleITK/SimpleITK.git # URL https://github.com/SimpleITK/SimpleITK/releases/download/v1.0.1/SimpleITK-1.0.1.tar.xz URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/SimpleITK_9d510bef.tar.gz URL_MD5 c34f4d5259594bf1adf1d83f13228cbe # PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/SimpleITK-0.8.1.patch INSTALL_COMMAND "" SOURCE_SUBDIR SuperBuild CMAKE_ARGS ${ep_common_cache_default_args} # -DCMAKE_BUILD_WITH_INSTALL_RPATH:BOOL=ON CMAKE_CACHE_ARGS ${ep_common_cache_args} ${additional_cmake_args} -DBUILD_SHARED_LIBS:BOOL=${_build_shared} -DSimpleITK_BUILD_DISTRIBUTE:BOOL=ON -DSimpleITK_PYTHON_THREADS:BOOL=ON -DSimpleITK_USE_SYSTEM_ITK:BOOL=ON -DITK_DIR:PATH=${ITK_DIR} -DSimpleITK_USE_SYSTEM_SWIG:BOOL=ON -DSWIG_DIR:PATH=${SWIG_DIR} -DSWIG_EXECUTABLE:FILEPATH=${SWIG_EXECUTABLE} -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_TESTING:BOOL=OFF -DGDCM_DIR:PATH=${GDCM_DIR} -DHDF5_DIR:PATH=${HDF5_DIR} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} -DCMAKE_CXX_COMPILER_AR:FILEPATH=${CMAKE_CXX_COMPILER_AR} -DCMAKE_CXX_COMPILER_RANLIB:FILEPATH=${CMAKE_CXX_COMPILER_RANLIB} -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_C_COMPILER_AR:FILEPATH=${CMAKE_C_COMPILER_AR} -DCMAKE_C_COMPILER_RANLIB:FILEPATH=${CMAKE_C_COMPILER_RANLIB} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) if( MITK_USE_Python ) set(_sitk_build_dir ${ep_prefix}/src/SimpleITK-build) # Build python distribution with easy install. If a own runtime is used # embed the egg into the site-package folder of the runtime # Note: Userbase install could also be relevant in some cases Probably windows wants to # install to Lib/python3.6/ # Build egg into custom user base folder and deploy it later into installer # https://pythonhosted.org/setuptools/easy_install.html#use-the-user-option-and-customize-pythonuserbase # PYTHONUSERBASE=${_install_dir} ${PYTHON_EXECUTABLE} setup.py --user # PythonDir needs to be fixed for the python interpreter by # changing dir delimiter for Windows set(_install_dir ${ep_prefix} ) set(_pythonpath ${ep_prefix}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages ) if(WIN32) STRING(REPLACE "/" "\\\\" _install_dir ${_install_dir}) + set(_additional_pythonpath $${ep_prefix}/Lib/site-packages) else() # escape spaces in the install path for linux STRING(REPLACE " " "\ " _install_dir ${_install_dir}) + set(_additional_pythonpath ) endif() ExternalProject_Add_Step(${proj} sitk_python_install_step - COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${_pythonpath}$${ep_prefix}/Lib/site-packages ${PYTHON_EXECUTABLE} Packaging/setup.py install --prefix=${_install_dir} + COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${_pythonpath}${_additional_pythonpath} ${PYTHON_EXECUTABLE} Packaging/setup.py install --prefix=${_install_dir} DEPENDEES install WORKING_DIRECTORY ${_sitk_build_dir}/SimpleITK-build/Wrapping/Python/ ) endif() mitkFunctionInstallExternalCMakeProject(${proj}) # Still need to install the SimpleITK Python wrappings else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() set(SimpleITK_DIR ${ep_prefix}/src/SimpleITK-build/SimpleITK-build) endif() diff --git a/Modules/CEST/src/mitkCustomTagParser.cpp b/Modules/CEST/src/mitkCustomTagParser.cpp index 635d3e1165..821ce29ba2 100644 --- a/Modules/CEST/src/mitkCustomTagParser.cpp +++ b/Modules/CEST/src/mitkCustomTagParser.cpp @@ -1,756 +1,757 @@ /*=================================================================== 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 "mitkCustomTagParser.h" #include #include #include #include "mitkIPropertyPersistence.h" #include "usGetModuleContext.h" #include "usModule.h" #include "usModuleContext.h" #include "usModuleResource.h" #include "usModuleResourceStream.h" #include #include #include #include #include #include #include #include namespace { mitk::IPropertyPersistence *GetPersistenceService() { mitk::IPropertyPersistence *result = nullptr; std::vector> persRegisters = us::GetModuleContext()->GetServiceReferences(); if (!persRegisters.empty()) { if (persRegisters.size() > 1) { MITK_WARN << "Multiple property description services found. Using just one."; } result = us::GetModuleContext()->GetService(persRegisters.front()); } return result; }; } const std::string mitk::CustomTagParser::m_CESTPropertyPrefix = "CEST."; const std::string mitk::CustomTagParser::m_OffsetsPropertyName = m_CESTPropertyPrefix + "Offsets"; const std::string mitk::CustomTagParser::m_RevisionPropertyName = m_CESTPropertyPrefix + "Revision"; const std::string mitk::CustomTagParser::m_JSONRevisionPropertyName = m_CESTPropertyPrefix + "revision_json"; const std::string mitk::CustomTagParser::m_RevisionIndependentMapping = "\n" " \"sProtConsistencyInfo.tSystemType\" : \"SysType\",\n" " \"sProtConsistencyInfo.flNominalB0\" : \"NominalB0\",\n" " \"sTXSPEC.asNucleusInfo[0].lFrequency\" : \"FREQ\",\n" " \"sTXSPEC.asNucleusInfo[0].flReferenceAmplitude\" : \"RefAmp\",\n" " \"alTR[0]\" : \"TR\",\n" " \"alTE[0]\" : \"TE\",\n" " \"lAverages\" : \"averages\",\n" " \"lRepetitions\" : \"repetitions\",\n" " \"adFlipAngleDegree[0]\" : \"ImageFlipAngle\",\n" " \"lTotalScanTimeSec\" : \"TotalScanTime\","; const std::string mitk::CustomTagParser::m_DefaultJsonString = "{\n" " \"default mapping, corresponds to revision 1416\" : \"revision_json\",\n" " \"sWiPMemBlock.alFree[1]\" : \"AdvancedMode\",\n" " \"sWiPMemBlock.alFree[2]\" : \"RecoveryMode\",\n" " \"sWiPMemBlock.alFree[3]\" : \"DoubleIrrMode\",\n" " \"sWiPMemBlock.alFree[4]\" : \"BinomMode\",\n" " \"sWiPMemBlock.alFree[5]\" : \"MtMode\",\n" " \"sWiPMemBlock.alFree[6]\" : \"PreparationType\",\n" " \"sWiPMemBlock.alFree[7]\" : \"PulseType\",\n" " \"sWiPMemBlock.alFree[8]\" : \"SamplingType\",\n" " \"sWiPMemBlock.alFree[9]\" : \"SpoilingType\",\n" " \"sWiPMemBlock.alFree[10]\" : \"measurements\",\n" " \"sWiPMemBlock.alFree[11]\" : \"NumberOfPulses\",\n" " \"sWiPMemBlock.alFree[12]\" : \"NumberOfLockingPulses\",\n" " \"sWiPMemBlock.alFree[13]\" : \"PulseDuration\",\n" " \"sWiPMemBlock.alFree[14]\" : \"DutyCycle\",\n" " \"sWiPMemBlock.alFree[15]\" : \"RecoveryTime\",\n" " \"sWiPMemBlock.alFree[16]\" : \"RecoveryTimeM0\",\n" " \"sWiPMemBlock.alFree[17]\" : \"ReadoutDelay\",\n" " \"sWiPMemBlock.alFree[18]\" : \"BinomDuration\",\n" " \"sWiPMemBlock.alFree[19]\" : \"BinomDistance\",\n" " \"sWiPMemBlock.alFree[20]\" : \"BinomNumberofPulses\",\n" " \"sWiPMemBlock.alFree[21]\" : \"BinomPreRepetions\",\n" " \"sWiPMemBlock.alFree[22]\" : \"BinomType\",\n" " \"sWiPMemBlock.adFree[1]\" : \"Offset\",\n" " \"sWiPMemBlock.adFree[2]\" : \"B1Amplitude\",\n" " \"sWiPMemBlock.adFree[3]\" : \"AdiabaticPulseMu\",\n" " \"sWiPMemBlock.adFree[4]\" : \"AdiabaticPulseBW\",\n" " \"sWiPMemBlock.adFree[5]\" : \"AdiabaticPulseLength\",\n" " \"sWiPMemBlock.adFree[6]\" : \"AdiabaticPulseAmp\",\n" " \"sWiPMemBlock.adFree[7]\" : \"FermiSlope\",\n" " \"sWiPMemBlock.adFree[8]\" : \"FermiFWHM\",\n" " \"sWiPMemBlock.adFree[9]\" : \"DoubleIrrDuration\",\n" " \"sWiPMemBlock.adFree[10]\" : \"DoubleIrrAmplitude\",\n" " \"sWiPMemBlock.adFree[11]\" : \"DoubleIrrRepetitions\",\n" " \"sWiPMemBlock.adFree[12]\" : \"DoubleIrrPreRepetitions\"\n" "}"; mitk::CustomTagParser::CustomTagParser(std::string relevantFile) : m_ClosestInternalRevision(""), m_ClosestExternalRevision("") { std::string pathToDirectory; std::string fileName; itksys::SystemTools::SplitProgramPath(relevantFile, pathToDirectory, fileName); m_DicomDataPath = pathToDirectory; m_ParseStrategy = "Automatic"; m_RevisionMappingStrategy = "Fuzzy"; } bool mitk::CustomTagParser::IsT1Sequence(std::string preparationType, std::string recoveryMode, std::string spoilingType, std::string revisionString) { bool isT1 = false; // if a forced parse strategy is set, use that one if ("T1" == m_ParseStrategy) { return true; } if ("CEST/WASABI" == m_ParseStrategy) { return false; } if (("T1Recovery" == preparationType) || ("T1Inversion" == preparationType)) { isT1 = true; } // How to interpret the recoveryMode depends on the age of the sequence // older sequences use 0 = false and 1 = true, newer ones 1 = false and 2 = true. // A rough rule of thumb is to assume that if the SpoilingType is 0, then the first // convention is chosen, if it is 1, then the second applies. Otherwise // we assume revision 1485 and newer to follow the new convention. // This unfortunate heuristic is due to somewhat arbitrary CEST sequence implementations. if (!isT1) { - std::string thisIsTrue = "0"; - std::string thisIsFalse = "1"; + std::string thisIsTrue = "1"; + std::string thisIsFalse = "0"; if ("0" == spoilingType) { thisIsFalse = "0"; thisIsTrue = "1"; } else if ("1" == spoilingType) { thisIsFalse = "1"; thisIsTrue = "2"; } else { - if (std::stoi(revisionString) - 1485 < 0) + int revisionNrWeAssumeToBeDifferenciating = 1485; + if (std::stoi(revisionString) - revisionNrWeAssumeToBeDifferenciating < 0) { thisIsFalse = "0"; thisIsTrue = "1"; } else { thisIsFalse = "1"; thisIsTrue = "2"; } } if (thisIsFalse == recoveryMode) { isT1 = false; } else if (thisIsTrue == recoveryMode) { isT1 = true; } } return isT1; } mitk::PropertyList::Pointer mitk::CustomTagParser::ParseDicomPropertyString(std::string dicomPropertyString) { auto results = mitk::PropertyList::New(); if ("" == dicomPropertyString) { //MITK_ERROR << "Could not parse empty custom dicom string"; return results; } std::map privateParameters; // convert hex to ascii // the Siemens private tag contains the information like this // "43\52\23\34" we jump over each \ and convert the number int len = dicomPropertyString.length(); std::string asciiString; for (int i = 0; i < len; i += 3) { std::string byte = dicomPropertyString.substr(i, 2); auto chr = (char)(int)strtol(byte.c_str(), nullptr, 16); asciiString.push_back(chr); } // extract parameter list std::size_t beginning = asciiString.find("### ASCCONV BEGIN ###") + 21; std::size_t ending = asciiString.find("### ASCCONV END ###"); std::string parameterListString = asciiString.substr(beginning, ending - beginning); boost::replace_all(parameterListString, "\r\n", "\n"); boost::char_separator newlineSeparator("\n"); boost::tokenizer> parameters(parameterListString, newlineSeparator); for (const auto ¶meter : parameters) { std::vector parts; boost::split(parts, parameter, boost::is_any_of("=")); if (parts.size() == 2) { parts[0].erase(std::remove(parts[0].begin(), parts[0].end(), ' '), parts[0].end()); parts[1].erase(parts[1].begin(), parts[1].begin() + 1); // first character is a space privateParameters[parts[0]] = parts[1]; } } // determine what revision we are using to handle parameters appropriately std::string revisionPrefix = "CEST_Rev"; std::string lowerRevisionPrefix = revisionPrefix; std::string lowerParameter = privateParameters["tSequenceFileName"]; std::transform(lowerRevisionPrefix.begin(), lowerRevisionPrefix.end(), lowerRevisionPrefix.begin(), ::tolower ); std::transform(lowerParameter.begin(), lowerParameter.end(), lowerParameter.begin(), ::tolower); std::size_t foundPosition = lowerParameter.find(lowerRevisionPrefix); if (foundPosition == std::string::npos) { MITK_ERROR << "Could not find revision information."; return results; } std::string revisionString = privateParameters["tSequenceFileName"].substr(foundPosition + revisionPrefix.length(), std::string::npos); std::size_t firstNonNumber = revisionString.find_first_not_of("0123456789"); revisionString.erase(firstNonNumber, std::string::npos); results->SetProperty(m_RevisionPropertyName, mitk::StringProperty::New(revisionString)); std::string jsonString = GetRevisionAppropriateJSONString(revisionString); boost::property_tree::ptree root; std::istringstream jsonStream(jsonString); try { boost::property_tree::read_json(jsonStream, root); } catch (boost::property_tree::json_parser_error e) { mitkThrow() << "Could not parse json file. Error was:\n" << e.what(); } for (auto it : root) { if (it.second.empty()) { std::string propertyName = m_CESTPropertyPrefix + it.second.data(); if (m_JSONRevisionPropertyName == propertyName) { results->SetProperty(propertyName, mitk::StringProperty::New(it.first)); } else { results->SetProperty(propertyName, mitk::StringProperty::New(privateParameters[it.first])); } } else { MITK_ERROR << "Currently no support for nested dicom tag descriptors in json file."; } } std::string sampling = ""; std::string offset = ""; std::string measurements = ""; bool hasSamplingInformation = results->GetStringProperty("CEST.SamplingType", sampling); results->GetStringProperty("CEST.Offset", offset); results->GetStringProperty("CEST.measurements", measurements); if ("" == measurements) { std::string stringRepetitions = ""; std::string stringAverages = ""; results->GetStringProperty("CEST.repetitions", stringRepetitions); results->GetStringProperty("CEST.averages", stringAverages); std::stringstream measurementStream; try { measurementStream << std::stoi(stringRepetitions) + std::stoi(stringAverages); measurements = measurementStream.str(); MITK_INFO << "Could not find measurements, assuming repetitions + averages. Which is: " << measurements; } catch (const std::invalid_argument &ia) { MITK_ERROR << "Could not find measurements, fallback assumption of repetitions + averages could not be determined either: " << ia.what(); } } std::string preparationType = ""; std::string recoveryMode = ""; std::string spoilingType = ""; results->GetStringProperty("CEST.PreparationType", preparationType); results->GetStringProperty("CEST.RecoveryMode", recoveryMode); results->GetStringProperty("CEST.SpoilingType", spoilingType); if (this->IsT1Sequence(preparationType, recoveryMode, spoilingType, revisionString)) { MITK_INFO << "Parsed as T1 image"; mitk::LocaleSwitch localeSwitch("C"); std::stringstream trecStream; std::string trecPath = m_DicomDataPath + "/TREC.txt"; std::ifstream list(trecPath.c_str()); if (list.good()) { std::string currentTime; while (std::getline(list, currentTime)) { trecStream << currentTime << " "; } } else { MITK_WARN << "Assumed T1, but could not load TREC at " << trecPath; } results->SetStringProperty("CEST.TREC", trecStream.str().c_str()); } else { MITK_INFO << "Parsed as CEST or WASABI image"; } if (hasSamplingInformation) { std::string offsets = GetOffsetString(sampling, offset, measurements); results->SetStringProperty(m_OffsetsPropertyName.c_str(), offsets.c_str()); } else { MITK_WARN << "Could not determine sampling type."; } //persist all properties mitk::IPropertyPersistence *persSrv = GetPersistenceService(); if (persSrv) { auto propertyMap = results->GetMap(); for (auto const &prop : *propertyMap) { PropertyPersistenceInfo::Pointer info = PropertyPersistenceInfo::New(); std::string key = prop.first; std::replace(key.begin(), key.end(), '.', '_'); info->SetNameAndKey(prop.first, key); persSrv->AddInfo(info); } } return results; } mitk::PropertyList::Pointer mitk::CustomTagParser::ParseDicomProperty(mitk::TemporoSpatialStringProperty *dicomProperty) { if (!dicomProperty) { MITK_ERROR << "DICOM property empty"; } auto results = mitk::PropertyList::New(); if (dicomProperty) { results = ParseDicomPropertyString(dicomProperty->GetValue()); } return results; } std::vector mitk::CustomTagParser::GetInternalRevisions() { const std::vector configs = us::GetModuleContext()->GetModule()->FindResources("/", "*.json", false); std::vector availableRevisionsVector; for (auto const resource : configs) { availableRevisionsVector.push_back(std::stoi(resource.GetBaseName())); } return availableRevisionsVector; } std::vector mitk::CustomTagParser::GetExternalRevisions() { std::string stringToJSONDirectory = GetExternalJSONDirectory(); std::string prospectiveJsonsPath = stringToJSONDirectory + "/*.json"; std::set JsonFiles; Poco::Glob::glob(prospectiveJsonsPath, JsonFiles, Poco::Glob::GLOB_CASELESS); std::vector availableRevisionsVector; for (auto const jsonpath : JsonFiles) { std::string jsonDir; std::string jsonName; itksys::SystemTools::SplitProgramPath(jsonpath, jsonDir, jsonName); std::string revision = itksys::SystemTools::GetFilenameWithoutExtension(jsonName); // disregard jsons which contain letters in their name bool onlyNumbers = (revision.find_first_not_of("0123456789") == std::string::npos); if(onlyNumbers) { availableRevisionsVector.push_back(std::stoi(revision)); } } return availableRevisionsVector; } std::string mitk::CustomTagParser::GetClosestLowerRevision(std::string revisionString, std::vector availableRevisionsVector) { // descending order std::sort(availableRevisionsVector.begin(), availableRevisionsVector.end(), std::greater<>()); int revision = std::stoi(revisionString); int index = 0; int numberOfRevisions = availableRevisionsVector.size(); while (index < numberOfRevisions) { // current mapping still has a higher revision number if ((availableRevisionsVector[index] - revision) > 0) { ++index; } else { break; } } if (index < numberOfRevisions) { std::stringstream foundRevisionStream; foundRevisionStream << availableRevisionsVector[index]; return foundRevisionStream.str(); } return ""; } void mitk::CustomTagParser::GetClosestLowerRevision(std::string revisionString) { m_ClosestInternalRevision = GetClosestLowerRevision(revisionString, GetInternalRevisions()); m_ClosestExternalRevision = GetClosestLowerRevision(revisionString, GetExternalRevisions()); if ("Strict" == m_RevisionMappingStrategy && !((0 == m_ClosestInternalRevision.compare(revisionString)) || (0 == m_ClosestExternalRevision.compare(revisionString)))) { // strict revision mapping and neither revision does match the dicom meta data std::stringstream errorMessageStream; errorMessageStream << "\nCould not parse dicom data in strict mode, data revision " << revisionString << " has no known matching parameter mapping. To use the closest known older parameter mapping select the " << "\"Fuzzy\" revision mapping option when loading the data.\n" << "\nCurrently known revision mappings are:\n Precompiled:"; for (const auto revision : GetInternalRevisions()) { errorMessageStream << " " << revision; } errorMessageStream << "\n External:"; for (const auto revision : GetExternalRevisions()) { errorMessageStream << " " << revision; } errorMessageStream << "\n\nExternal revision mapping descriptions should be located at\n\n"; std::string stringToJSONDirectory = GetExternalJSONDirectory(); errorMessageStream << stringToJSONDirectory; errorMessageStream << "\n\nTo provide an external mapping for this revision create a " << revisionString << ".json there. You might need to create the directory first."; mitkThrow() << errorMessageStream.str(); } } std::string mitk::CustomTagParser::GetRevisionAppropriateJSONString(std::string revisionString) { std::string returnValue = ""; if ("" == revisionString) { MITK_WARN << "Could not extract revision"; } else { GetClosestLowerRevision(revisionString); bool useExternal = false; bool useInternal = false; if ("" != m_ClosestExternalRevision) { useExternal = true; } if ("" != m_ClosestInternalRevision) { useInternal = true; } if (useExternal && useInternal) { if (std::stoi(m_ClosestInternalRevision) > std::stoi(m_ClosestExternalRevision)) { useExternal = false; } } if (useExternal) { std::string stringToJSONDirectory = GetExternalJSONDirectory(); std::string prospectiveJsonPath = stringToJSONDirectory + "/" + m_ClosestExternalRevision + ".json"; std::ifstream externalJSON(prospectiveJsonPath.c_str()); if (externalJSON.good()) { MITK_INFO << "Found external json for CEST parameters at " << prospectiveJsonPath; std::stringstream buffer; buffer << externalJSON.rdbuf(); returnValue = buffer.str(); useInternal = false; } } if (useInternal) { std::string filename = m_ClosestInternalRevision + ".json"; us::ModuleResource jsonResource = us::GetModuleContext()->GetModule()->GetResource(filename); if (jsonResource.IsValid() && jsonResource.IsFile()) { MITK_INFO << "Found no external json for CEST parameters. Closest internal mapping is for revision " << m_ClosestInternalRevision; us::ModuleResourceStream jsonStream(jsonResource); std::stringstream buffer; buffer << jsonStream.rdbuf(); returnValue = buffer.str(); } } } if ("" == returnValue) { MITK_WARN << "Could not identify parameter mapping for the given revision " << revisionString << ", using default mapping."; returnValue = m_DefaultJsonString; } // inject the revision independent mapping before the first newline { returnValue.insert(returnValue.find("\n"), m_RevisionIndependentMapping); } return returnValue; } std::string mitk::CustomTagParser::GetOffsetString(std::string samplingType, std::string offset, std::string measurements) { mitk::LocaleSwitch localeSwitch("C"); std::stringstream results; std::string normalizationIndicatingOffset = "-300"; double offsetDouble = 0.0; int measurementsInt = 0; bool validOffset = false; bool validMeasurements = false; if ("" != offset) { validOffset = true; offsetDouble = std::stod(offset); } if ("" != measurements) { validMeasurements = true; measurementsInt = std::stoi(measurements); } std::vector offsetVector; if (validOffset && validMeasurements) { for (int step = 0; step < measurementsInt -1; ++step) { double currentOffset = -offsetDouble + 2 * step * offsetDouble / (measurementsInt - 2.0); offsetVector.push_back(currentOffset); } } else { MITK_WARN << "Invalid offset or measurements, offset calculation will only work for list sampling type."; } if (samplingType == "1" || samplingType == "Regular") { if (validOffset && validMeasurements) { results << normalizationIndicatingOffset << " "; for (const auto& entry : offsetVector) { results << entry << " "; } } } else if (samplingType == "2" || samplingType == "Alternating") { if (validOffset && validMeasurements) { results << normalizationIndicatingOffset << " "; for (auto& entry : offsetVector) { entry = std::abs(entry); } std::sort(offsetVector.begin(), offsetVector.end(), std::greater<>()); for (unsigned int index = 0; index < offsetVector.size(); ++index) { offsetVector[index] = std::pow(-1, index) * offsetVector[index]; } for (auto& entry : offsetVector) { results << entry << " "; } } } else if (samplingType == "3" || samplingType == "List") { std::string listPath = m_DicomDataPath + "/LIST.txt"; std::ifstream list(listPath.c_str()); if (list.good()) { std::string currentOffset; while (std::getline(list, currentOffset)) { results << currentOffset << " "; } } else { MITK_ERROR << "Could not load list at " << listPath; } } else if (samplingType == "4" || samplingType == "SingleOffset") { if (validOffset && validMeasurements) { results << normalizationIndicatingOffset << " "; for (int step = 0; step < measurementsInt - 1; ++step) { results << offsetDouble << " "; } } } else { MITK_WARN << "Encountered unknown sampling type."; } std::string resultString = results.str(); // replace multiple spaces by a single space std::string::iterator newEnditerator = std::unique(resultString.begin(), resultString.end(), [=](char lhs, char rhs) { return (lhs == rhs) && (lhs == ' '); } ); resultString.erase(newEnditerator, resultString.end()); if ((resultString.length() > 0) && (resultString.at(resultString.length() - 1) == ' ')) { resultString.erase(resultString.end() - 1, resultString.end()); } if ((resultString.length() > 0) && (resultString.at(0) == ' ')) { resultString.erase(resultString.begin(), ++(resultString.begin())); } return resultString; } void mitk::CustomTagParser::SetParseStrategy(std::string parseStrategy) { m_ParseStrategy = parseStrategy; } void mitk::CustomTagParser::SetRevisionMappingStrategy(std::string revisionMappingStrategy) { m_RevisionMappingStrategy = revisionMappingStrategy; } std::string mitk::CustomTagParser::GetExternalJSONDirectory() { std::string moduleLocation = us::GetModuleContext()->GetModule()->GetLocation(); std::string stringToModule; std::string libraryName; itksys::SystemTools::SplitProgramPath(moduleLocation, stringToModule, libraryName); std::stringstream jsonDirectory; jsonDirectory << stringToModule << "/CESTRevisionMapping"; return jsonDirectory.str(); } diff --git a/Modules/Classification/CLMiniApps/XRaxSimulationFromCT.cpp b/Modules/Classification/CLMiniApps/XRaxSimulationFromCT.cpp index 0cdc98a1c1..ebd97e602d 100644 --- a/Modules/Classification/CLMiniApps/XRaxSimulationFromCT.cpp +++ b/Modules/Classification/CLMiniApps/XRaxSimulationFromCT.cpp @@ -1,226 +1,225 @@ /*=================================================================== 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 "mitkProperties.h" #include "mitkCommandLineParser.h" #include "mitkIOUtil.h" #include "itkImageRegionIterator.h" // MITK #include #include #include struct Params { bool invert; float zeroValue; }; - template void CreateXRay(itk::Image* itkImage, mitk::Image::Pointer mask1, std::string output, Params param) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::Image NewImageType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask1, itkMask); NewImageType::SpacingType newSpacing; - auto spacing = itkImage->GetSpacing(); - spacing[0] = itkImage->GetSpacing()[0]; - spacing[1] = itkImage->GetSpacing()[1]; - spacing[2] = itkImage->GetSpacing()[2]; + typename ImageType::SpacingType spacing; + spacing[0] = 0; + spacing[1] = 0; + spacing[2] = 0; spacing = itkImage->GetSpacing(); NewImageType::RegionType region1,region2,region3,region1m,region2m,region3m; NewImageType::IndexType start; start[0] = 0; start[1] = 0; NewImageType::SizeType size1, size2, size3; size1[0] = mask1->GetDimensions()[0]; size2[0] = mask1->GetDimensions()[0]; size3[0] = mask1->GetDimensions()[1]; size1[1] = mask1->GetDimensions()[1]; size2[1] = mask1->GetDimensions()[2]; size3[1] = mask1->GetDimensions()[2]; region1.SetSize(size1); region1m.SetSize(size1); region2.SetSize(size2); region2m.SetSize(size2); region3.SetSize(size3); region3m.SetSize(size3); region1.SetIndex(start); region1m.SetIndex(start); region2.SetIndex(start); region2m.SetIndex(start); region3.SetIndex(start); region3m.SetIndex(start); NewImageType::Pointer image1 = NewImageType::New(); image1->SetRegions(region1); image1->Allocate(); image1->FillBuffer(0); newSpacing[0] = spacing[0]; newSpacing[1] = spacing[1]; image1->SetSpacing(newSpacing); NewImageType::Pointer image2 = NewImageType::New(); image2->SetRegions(region2); image2->Allocate(); image2->FillBuffer(0); newSpacing[0] = spacing[0]; newSpacing[1] = spacing[2]; image2->SetSpacing(newSpacing); NewImageType::Pointer image3 = NewImageType::New(); image3->SetRegions(region3); image3->Allocate(); image3->FillBuffer(0); newSpacing[0] = spacing[1]; newSpacing[1] = spacing[2]; image3->SetSpacing(newSpacing); NewImageType::Pointer image1m = NewImageType::New(); image1m->SetRegions(region1m); image1m->Allocate(); image1m->FillBuffer(0); newSpacing[0] = spacing[0]; newSpacing[1] = spacing[1]; image1m->SetSpacing(newSpacing); NewImageType::Pointer image2m = NewImageType::New(); image2m->SetRegions(region2m); image2m->Allocate(); image2m->FillBuffer(0); newSpacing[0] = spacing[0]; newSpacing[1] = spacing[2]; image2m->SetSpacing(newSpacing); NewImageType::Pointer image3m = NewImageType::New(); image3m->SetRegions(region3m); image3m->Allocate(); image3m->FillBuffer(0); newSpacing[0] = spacing[1]; newSpacing[1] = spacing[2]; image3m->SetSpacing(newSpacing); for (unsigned int x = 0; x < mask1->GetDimensions()[0]; ++x) { for (unsigned int y = 0; y < mask1->GetDimensions()[1]; ++y) { for (unsigned int z = 0; z < mask1->GetDimensions()[2]; ++z) { NewImageType::IndexType newIndex; typename ImageType::IndexType index; index[0] = x; index[1] = y; index[2] = z; double pixel = itkImage->GetPixel(index)+1024; pixel = pixel / 1000.0; pixel = (pixel < 0)? 0 : pixel; newIndex[0] = x; newIndex[1] = y; image1->SetPixel(newIndex, image1->GetPixel(newIndex) + pixel); newIndex[0] = x; newIndex[1] = z; image2->SetPixel(newIndex, image2->GetPixel(newIndex) + pixel); newIndex[0] = y; newIndex[1] = z; image3->SetPixel(newIndex, image3->GetPixel(newIndex) + pixel); if (itkMask->GetPixel(index) > 0 && !param.invert) { pixel = param.zeroValue + 1024; pixel = pixel / 1000.0; } if (itkMask->GetPixel(index) < 1 && param.invert) { pixel = param.zeroValue + 1024; pixel = pixel / 1000.0; } pixel = (pixel < 0)? 0 : pixel; newIndex[0] = x; newIndex[1] = y; image1m->SetPixel(newIndex, image1m->GetPixel(newIndex) + pixel); newIndex[0] = x; newIndex[1] = z; image2m->SetPixel(newIndex, image2m->GetPixel(newIndex) + pixel); newIndex[0] = y; newIndex[1] = z; image3m->SetPixel(newIndex, image3m->GetPixel(newIndex) + pixel); } } } mitk::Image::Pointer img = mitk::ImportItkImage(image1); mitk::IOUtil::Save(img, output + "1.nrrd"); img = mitk::ImportItkImage(image2); mitk::IOUtil::Save(img, output + "2.nrrd"); img = mitk::ImportItkImage(image3); mitk::IOUtil::Save(img, output + "3.nrrd"); img = mitk::ImportItkImage(image1m); mitk::IOUtil::Save(img, output + "1m.nrrd"); img = mitk::ImportItkImage(image2m); mitk::IOUtil::Save(img, output + "2m.nrrd"); img = mitk::ImportItkImage(image3m); mitk::IOUtil::Save(img, output + "3m.nrrd"); } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Dicom Loader"); parser.setCategory("Preprocessing Tools"); parser.setDescription(""); parser.setContributor("MBI"); parser.setArgumentPrefix("-","-"); // Add command line argument names parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.addArgument("input", "i", mitkCommandLineParser::InputDirectory, "Input image:", "Input folder", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputDirectory, "Input mask:", "Input folder", us::Any(), false); parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file", us::Any(), false); parser.addArgument("invert", "invert", mitkCommandLineParser::Bool, "Input mask:", "Input folder", us::Any()); parser.addArgument("zero_value", "zero", mitkCommandLineParser::Float, "Output file:", "Output file", us::Any()); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // Show a help message if ( parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } std::string inputImage = us::any_cast(parsedArgs["input"]); MITK_INFO << inputImage; std::string inputMask = us::any_cast(parsedArgs["mask"]); MITK_INFO << inputMask; Params param; param.invert = false; param.zeroValue = 0; if (parsedArgs.count("invert")) { param.invert = true; } if (parsedArgs.count("zero_value")) { param.zeroValue = us::any_cast(parsedArgs["zero_value"]); } mitk::Image::Pointer image = mitk::IOUtil::Load(inputImage); mitk::Image::Pointer mask = mitk::IOUtil::Load(inputMask); AccessByItk_3(image, CreateXRay, mask, parsedArgs["output"].ToString(),param); //const mitk::Image::Pointer image = *imageIter; //mitk::IOUtil::SaveImage(image,outFileName); return EXIT_SUCCESS; } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp index 07c9c40c6a..6458c7f8ac 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp @@ -1,540 +1,529 @@ /*=================================================================== 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 // MITK #include #include #include #include #include // ITK #include #include #include #include // VTK #include #include #include #include #include #include #include #include // STL #include #include // Eigen #include struct GIFVolumetricDensityStatisticsParameters { double volume; std::string prefix; }; template void CalculateVolumeDensityStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, GIFVolumetricDensityStatisticsParameters params, mitk::GIFVolumetricDensityStatistics::FeatureListType & featureList) { typedef itk::Image ImageType; typedef itk::Image MaskType; double volume = params.volume; std::string prefix = params.prefix; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); itk::ImageRegionConstIteratorWithIndex imgA(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex imgB(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maskA(maskImage, maskImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maskB(maskImage, maskImage->GetLargestPossibleRegion()); double moranA = 0; double moranB = 0; double geary = 0; double Nv = 0; double w_ij = 0; double mean = 0; typename ImageType::PointType pointA; typename ImageType::PointType pointB; - std::cout << "GIFVolumetric Begin Image Mean Calcuation " << std::endl; while (!imgA.IsAtEnd()) { if (maskA.Get() > 0) { Nv += 1; mean += imgA.Get(); } ++imgA; ++maskA; } mean /= Nv; imgA.GoToBegin(); maskA.GoToBegin(); - - std::cout << "GIFVolumetric Begin Image MoranB Calcuation " << std::endl; while (!imgA.IsAtEnd()) { if (maskA.Get() > 0) { imgB.GoToBegin(); maskB.GoToBegin(); while (!imgB.IsAtEnd()) { if ((imgA.GetIndex() == imgB.GetIndex()) || (maskB.Get() < 1)) { ++imgB; ++maskB; continue; } itkImage->TransformIndexToPhysicalPoint(maskA.GetIndex(), pointA); itkImage->TransformIndexToPhysicalPoint(maskB.GetIndex(), pointB); double w = 1 / pointA.EuclideanDistanceTo(pointB); moranA += w*(imgA.Get() - mean)* (imgB.Get() - mean); geary += w * (imgA.Get() - imgB.Get()) * (imgA.Get() - imgB.Get()); w_ij += w; ++imgB; ++maskB; } moranB += (imgA.Get() - mean)* (imgA.Get() - mean); } ++imgA; ++maskA; } featureList.push_back(std::make_pair(prefix + "Volume integrated intensity", volume* mean)); featureList.push_back(std::make_pair(prefix + "Volume Moran's I index", Nv / w_ij * moranA / moranB)); featureList.push_back(std::make_pair(prefix + "Volume Geary's C measure", ( Nv -1 ) / 2 / w_ij * geary/ moranB)); } void calculateMOBB(vtkPointSet *pointset, double &volume, double &surface) { volume = std::numeric_limits::max(); for (int cellID = 0; cellID < pointset->GetNumberOfCells(); ++cellID) { auto cell = pointset->GetCell(cellID); for (int edgeID = 0; edgeID < 3; ++edgeID) { auto edge = cell->GetEdge(edgeID); double pA[3], pB[3]; double pAA[3], pBB[3]; vtkSmartPointer transform = vtkSmartPointer::New(); transform->PostMultiply(); pointset->GetPoint(edge->GetPointId(0), pA); pointset->GetPoint(edge->GetPointId(1), pB); double angleZ = std::atan2((- pA[2] + pB[2]) ,(pA[1] - pB[1])); angleZ *= 180 / vnl_math::pi; if (pA[2] == pB[2]) angleZ = 0; transform->RotateX(angleZ); transform->TransformPoint(pA, pAA); transform->TransformPoint(pB, pBB); double angleY = std::atan2((pAA[1] -pBB[1]) ,-(pAA[0] - pBB[0])); angleY *= 180 / vnl_math::pi; if (pAA[1] == pBB[1]) angleY = 0; transform->RotateZ(angleY); double p0[3]; pointset->GetPoint(edge->GetPointId(0), p0); double curMinX = std::numeric_limits::max(); double curMaxX = std::numeric_limits::lowest(); double curMinY = std::numeric_limits::max(); double curMaxY = std::numeric_limits::lowest(); double curMinZ = std::numeric_limits::max(); double curMaxZ = std::numeric_limits::lowest(); for (int pointID = 0; pointID < pointset->GetNumberOfPoints(); ++pointID) { double p[3]; double p2[3]; pointset->GetPoint(pointID, p); p[0] -= p0[0]; p[1] -= p0[1]; p[2] -= p0[2]; transform->TransformPoint(p, p2); curMinX = std::min(p2[0], curMinX); curMaxX = std::max(p2[0], curMaxX); curMinY = std::min(p2[1], curMinY); curMaxY = std::max(p2[1], curMaxY); curMinZ = std::min(p2[2], curMinZ); curMaxZ = std::max(p2[2], curMaxZ); - - //std::cout << pointID << " (" << p[0] << "|" << p[1] << "|" << p[2] << ") (" << p2[0] << "|" << p2[1] << "|" << p2[2] << ")" << std::endl; } if ((curMaxX - curMinX)*(curMaxY - curMinY)*(curMaxZ - curMinZ) < volume) { volume = (curMaxX - curMinX)*(curMaxY - curMinY)*(curMaxZ - curMinZ); surface = (curMaxX - curMinX)*(curMaxX - curMinX) + (curMaxY - curMinY)*(curMaxY - curMinY) + (curMaxZ - curMinZ)*(curMaxZ - curMinZ); surface *= 2; } } } } -void calculateMEE(vtkPointSet *pointset, double &vol, double &surf, double tolerance=0.0000001) +void calculateMEE(vtkPointSet *pointset, double &vol, double &surf, double tolerance=0.0001) { // Inspired by https://github.com/smdabdoub/ProkaryMetrics/blob/master/calc/fitting.py int numberOfPoints = pointset->GetNumberOfPoints(); int dimension = 3; Eigen::MatrixXd points(3, numberOfPoints); Eigen::MatrixXd Q(3+1, numberOfPoints); double p[3]; std::cout << "Initialize Q " << std::endl; for (int i = 0; i < numberOfPoints; ++i) { pointset->GetPoint(i, p); points(0, i) = p[0]; points(1, i) = p[1]; points(2, i) = p[2]; Q(0, i) = p[0]; Q(1, i) = p[1]; Q(2, i) = p[2]; - Q(3, i) = p[3]; + Q(3, i) = 1.0; } int count = 1; double error = 1; Eigen::VectorXd u_vector(numberOfPoints); u_vector.fill(1.0 / numberOfPoints); Eigen::DiagonalMatrix u = u_vector.asDiagonal(); Eigen::VectorXd ones(dimension + 1); ones.fill(1); Eigen::MatrixXd Ones = ones.asDiagonal(); // Khachiyan Algorithm - std::cout << "GIFVolumetric Start Khachyan Algorithm " << tolerance << std::endl; while (error > tolerance) { - - std::cout << "GIFVolumetric Next K Loop: " << std::endl; auto Qt = Q.transpose(); Eigen::MatrixXd X = Q*u*Qt; Eigen::FullPivHouseholderQR qr(X); Eigen::MatrixXd Xi = qr.solve(Ones); + Eigen::MatrixXd M = Qt * Xi * Q; double maximumValue = M(0, 0); int maximumPosition = 0; for (int i = 0; i < numberOfPoints; ++i) { if (maximumValue < M(i, i)) { maximumValue = M(i, i); maximumPosition = i; } } double stepsize = (maximumValue - dimension - 1) / ((dimension + 1) * (maximumValue - 1)); - std::cout << "GIFVolumetric Max Val+Stepsize " << maximumValue << " - " << stepsize<< std::endl; Eigen::DiagonalMatrix new_u = (1.0 - stepsize) * u; new_u.diagonal()[maximumPosition] = (new_u.diagonal())(maximumPosition) + stepsize; ++count; error = (new_u.diagonal() - u.diagonal()).norm(); u.diagonal() = new_u.diagonal(); } // U = u - std::cout << "GIFVolumetric Decomposition U=u" << std::endl; Eigen::MatrixXd Ai = points * u * points.transpose() - points * u *(points * u).transpose(); Eigen::FullPivHouseholderQR qr(Ai); Eigen::VectorXd ones2(dimension); ones2.fill(1); Eigen::MatrixXd Ones2 = ones2.asDiagonal(); Eigen::MatrixXd A = qr.solve(Ones2)*1.0/dimension; Eigen::JacobiSVD svd(A); double c = 1 / sqrt(svd.singularValues()[0]); double b = 1 / sqrt(svd.singularValues()[1]); double a = 1 / sqrt(svd.singularValues()[2]); double V = 4 * vnl_math::pi*a*b*c / 3; - std::cout << "GIFVolumetric c,b,a,V: " << c << " - " << b << " - " << a << " - " << V << std::endl; - double ad_mvee= 0; double alpha = std::sqrt(1 - b*b / a / a); double beta = std::sqrt(1 - c*c / a / a); for (int i = 0; i < 20; ++i) { ad_mvee += 4 * vnl_math::pi*a*b*(alpha*alpha + beta*beta) / (2 * alpha*beta) * (std::pow(alpha*beta, i)) / (1 - 4 * i*i); } vol = V; surf = ad_mvee; } mitk::GIFVolumetricDensityStatistics::FeatureListType mitk::GIFVolumetricDensityStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } std::string prefix = FeatureDescriptionPrefix(); vtkSmartPointer mesher = vtkSmartPointer::New(); vtkSmartPointer stats = vtkSmartPointer::New(); vtkSmartPointer stats2 = vtkSmartPointer::New(); mesher->SetInputData(mask->GetVtkImageData()); mesher->SetValue(0, 0.5); stats->SetInputConnection(mesher->GetOutputPort()); stats->Update(); vtkSmartPointer delaunay = vtkSmartPointer< vtkDelaunay3D >::New(); delaunay->SetInputConnection(mesher->GetOutputPort()); delaunay->SetAlpha(0); delaunay->Update(); vtkSmartPointer geometryFilter = vtkSmartPointer::New(); geometryFilter->SetInputConnection(delaunay->GetOutputPort()); geometryFilter->Update(); stats2->SetInputConnection(geometryFilter->GetOutputPort()); stats2->Update(); double vol_mvee; double surf_mvee; calculateMEE(mesher->GetOutput(), vol_mvee, surf_mvee); double vol_mobb; double surf_mobb; calculateMOBB(geometryFilter->GetOutput(), vol_mobb, surf_mobb); double pi = vnl_math::pi; double meshVolume = stats->GetVolume(); double meshSurf = stats->GetSurfaceArea(); GIFVolumetricDensityStatisticsParameters params; params.volume = meshVolume; params.prefix = prefix; AccessByItk_3(image, CalculateVolumeDensityStatistic, mask, params, featureList); //Calculate center of mass shift int xx = mask->GetDimensions()[0]; int yy = mask->GetDimensions()[1]; int zz = mask->GetDimensions()[2]; double xd = mask->GetGeometry()->GetSpacing()[0]; double yd = mask->GetGeometry()->GetSpacing()[1]; double zd = mask->GetGeometry()->GetSpacing()[2]; int minimumX=xx; int maximumX=0; int minimumY=yy; int maximumY=0; int minimumZ=zz; int maximumZ=0; vtkSmartPointer dataset1Arr = vtkSmartPointer::New(); vtkSmartPointer dataset2Arr = vtkSmartPointer::New(); vtkSmartPointer dataset3Arr = vtkSmartPointer::New(); dataset1Arr->SetNumberOfComponents(1); dataset2Arr->SetNumberOfComponents(1); dataset3Arr->SetNumberOfComponents(1); dataset1Arr->SetName("M1"); dataset2Arr->SetName("M2"); dataset3Arr->SetName("M3"); vtkSmartPointer dataset1ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset2ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset3ArrU = vtkSmartPointer::New(); dataset1ArrU->SetNumberOfComponents(1); dataset2ArrU->SetNumberOfComponents(1); dataset3ArrU->SetNumberOfComponents(1); dataset1ArrU->SetName("M1"); dataset2ArrU->SetName("M2"); dataset3ArrU->SetName("M3"); vtkSmartPointer points = vtkSmartPointer< vtkPoints >::New(); for (int x = 0; x < xx; x++) { for (int y = 0; y < yy; y++) { for (int z = 0; z < zz; z++) { itk::Image::IndexType index; index[0] = x; index[1] = y; index[2] = z; mitk::ScalarType pxImage; mitk::ScalarType pxMask; mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(), index, pxImage, 0); mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, mask->GetChannelDescriptor().GetPixelType(), mask, mask->GetVolumeData(), index, pxMask, 0); //Check if voxel is contained in segmentation if (pxMask > 0) { minimumX = std::min(x, minimumX); minimumY = std::min(y, minimumY); minimumZ = std::min(z, minimumZ); maximumX = std::max(x, maximumX); maximumY = std::max(y, maximumY); maximumZ = std::max(z, maximumZ); points->InsertNextPoint(x*xd, y*yd, z*zd); if (pxImage == pxImage) { dataset1Arr->InsertNextValue(x*xd); dataset2Arr->InsertNextValue(y*yd); dataset3Arr->InsertNextValue(z*zd); } } } } } vtkSmartPointer datasetTable = vtkSmartPointer::New(); datasetTable->AddColumn(dataset1Arr); datasetTable->AddColumn(dataset2Arr); datasetTable->AddColumn(dataset3Arr); vtkSmartPointer pcaStatistics = vtkSmartPointer::New(); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTable); pcaStatistics->SetColumnStatus("M1", 1); pcaStatistics->SetColumnStatus("M2", 1); pcaStatistics->SetColumnStatus("M3", 1); pcaStatistics->RequestSelectedColumns(); pcaStatistics->SetDeriveOption(true); pcaStatistics->Update(); vtkSmartPointer eigenvalues = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvalues); std::vector eigen_val(3); eigen_val[2] = eigenvalues->GetValue(0); eigen_val[1] = eigenvalues->GetValue(1); eigen_val[0] = eigenvalues->GetValue(2); double major = 2*sqrt(eigen_val[2]); double minor = 2*sqrt(eigen_val[1]); double least = 2*sqrt(eigen_val[0]); double alpha = std::sqrt(1 - minor*minor / major / major); double beta = std::sqrt(1 - least*least / major / major); double a = (maximumX - minimumX+1) * xd; double b = (maximumY - minimumY+1) * yd; double c = (maximumZ - minimumZ+1) * zd; double vd_aabb = meshVolume / (a*b*c); double ad_aabb = meshSurf / (2 * a*b + 2 * a*c + 2 * b*c); double vd_aee = 3 * meshVolume / (4.0*pi*major*minor*least); double ad_aee = 0; for (int i = 0; i < 20; ++i) { ad_aee += 4 * pi*major*minor*(alpha*alpha + beta*beta) / (2 * alpha*beta) * (std::pow(alpha*beta, i)) / (1 - 4 * i*i); } ad_aee = meshSurf / ad_aee; double vd_ch = meshVolume / stats2->GetVolume(); double ad_ch = meshSurf / stats2->GetSurfaceArea(); featureList.push_back(std::make_pair(prefix + "Volume density axis-aligned bounding box", vd_aabb)); featureList.push_back(std::make_pair(prefix + "Surface density axis-aligned bounding box", ad_aabb)); featureList.push_back(std::make_pair(prefix + "Volume density oriented minimum bounding box", meshVolume / vol_mobb)); featureList.push_back(std::make_pair(prefix + "Surface density oriented minimum bounding box", meshSurf / surf_mobb)); featureList.push_back(std::make_pair(prefix + "Volume density approx. enclosing ellipsoid", vd_aee)); featureList.push_back(std::make_pair(prefix + "Surface density approx. enclosing ellipsoid", ad_aee)); featureList.push_back(std::make_pair(prefix + "Volume density approx. minimum volume enclosing ellipsoid", meshVolume / vol_mvee)); featureList.push_back(std::make_pair(prefix + "Surface density approx. minimum volume enclosing ellipsoid", meshSurf / surf_mvee)); featureList.push_back(std::make_pair(prefix + "Volume density convex hull", vd_ch)); featureList.push_back(std::make_pair(prefix + "Surface density convex hull", ad_ch)); return featureList; } mitk::GIFVolumetricDensityStatistics::GIFVolumetricDensityStatistics() { SetLongName("volume-density"); SetShortName("volden"); SetFeatureClassName("Morphological Density"); } mitk::GIFVolumetricDensityStatistics::FeatureNameListType mitk::GIFVolumetricDensityStatistics::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFVolumetricDensityStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Density Statistic", "calculates volume density based features", us::Any()); } void mitk::GIFVolumetricDensityStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating volumetric density features ...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating volumetric density features...."; } } diff --git a/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp index adde06ef97..d29ae3f58b 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp @@ -1,92 +1,92 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFVolumetricDensityStatisticsTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFVolumetricDensityStatisticsTestSuite); MITK_TEST(ImageDescription_PhantomTest); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest() { mitk::GIFVolumetricDensityStatistics::Pointer featureCalculator = mitk::GIFVolumetricDensityStatistics::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { MITK_INFO << valuePair.first << " : " << valuePair.second; results[valuePair.first] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 13 features.", std::size_t(13), featureList.size()); // These values are obtained by a run of the filter. // The might be wrong! // These values are obtained in collaboration with IBSI. // They are usually reported with an accuracy of 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume integrated intensity with Large IBSI Phantom Image", 1195, results["Morphological Density::Volume integrated intensity"], 1.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Moran's I index with Large IBSI Phantom Image", 0.0397, results["Morphological Density::Volume Moran's I index"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Geary's C measure with Large IBSI Phantom Image", 0.974, results["Morphological Density::Volume Geary's C measure"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume density axis-aligned bounding box with Large IBSI Phantom Image", 0.87, results["Morphological Density::Volume density axis-aligned bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume density axis-aligned bounding box with Large IBSI Phantom Image", 0.87, results["Morphological Density::Surface density axis-aligned bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume oriented minimum bounding box with Large IBSI Phantom Image", 0.87, results["Morphological Density::Volume density oriented minimum bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume oriented minimum bounding box with Large IBSI Phantom Image", 0.86, results["Morphological Density::Surface density oriented minimum bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume approx. enclosing ellipsoid with Large IBSI Phantom Image", 1.17, results["Morphological Density::Volume density approx. enclosing ellipsoid"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume approx. enclosing ellipsoid with Large IBSI Phantom Image", 1.34, results["Morphological Density::Surface density approx. enclosing ellipsoid"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume minimum volume enclosing ellipsoid with Large IBSI Phantom Image", 0.24, results["Morphological Density::Volume density approx. minimum volume enclosing ellipsoid"], 0.01); - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume minimum volume enclosing ellipsoid with Large IBSI Phantom Image", 0.46, results["Morphological Density::Surface density approx. minimum volume enclosing ellipsoid"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume minimum volume enclosing ellipsoid with Large IBSI Phantom Image", 0.49, results["Morphological Density::Surface density approx. minimum volume enclosing ellipsoid"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume convex hull with Large IBSI Phantom Image", 0.96, results["Morphological Density::Volume density convex hull"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume convex hull with Large IBSI Phantom Image", 1.03, results["Morphological Density::Surface density convex hull"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFVolumetricDensityStatistics ) \ No newline at end of file diff --git a/Modules/Core/test/mitkSurfaceTest.cpp b/Modules/Core/test/mitkSurfaceTest.cpp index 4dcb8ab986..5551ab13aa 100644 --- a/Modules/Core/test/mitkSurfaceTest.cpp +++ b/Modules/Core/test/mitkSurfaceTest.cpp @@ -1,287 +1,279 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Testing #include "mitkTestFixture.h" #include // std includes #include // MITK includes #include "mitkCommon.h" #include "mitkNumericTypes.h" #include "mitkSurface.h" // MITK includes #include // VTK includes #include "vtkPolyData.h" #include "vtkSphereSource.h" // stream includes #include class mitkSurfaceTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkSurfaceTestSuite); MITK_TEST(InitializationSurfacePointer_Success); MITK_TEST(InitializationCloneSurfacePointer_Success); MITK_TEST(StateOfVtkPolyDataEqualNullPointer_Success); MITK_TEST(SetVtkPolyDataNotNullPointer_Failure); MITK_TEST(SetClonedVtkPolyDataNotNullPointer_Failure); MITK_TEST(GetBoundingBox_Success); MITK_TEST(SurfaceExpandTimestepsAreFive_Success); MITK_TEST(Surface4DDataCreation_Success); MITK_TEST(TimeGeometrySurface_Success); MITK_TEST(ChangingDataOfSpecificTimestepSurface_Success); MITK_TEST(SurfaceCopyWithGraft_Failure); MITK_TEST(CopyingNumberOfTimesteps_Success); MITK_TEST(DestructionOfSurface_Success); CPPUNIT_TEST_SUITE_END(); private: mitk::Surface::Pointer m_Surface; mitk::Surface::Pointer m_CloneSurface; - vtkSphereSource *m_SphereSource; + vtkSmartPointer m_SphereSource; const mitk::TimeGeometry *m_InputTimeGeometry; int m_Time; int m_Timestep; public: void setUp() { m_Surface = mitk::Surface::New(); m_CloneSurface = m_Surface->Clone(); - m_SphereSource = vtkSphereSource::New(); + m_SphereSource = vtkSmartPointer::New(); m_InputTimeGeometry = m_Surface->GetUpdatedTimeGeometry(); m_SphereSource->SetCenter(0, 0, 0); m_SphereSource->SetRadius(5.0); m_SphereSource->SetThetaResolution(10); m_SphereSource->SetPhiResolution(10); m_SphereSource->Update(); m_Time = 3; m_Timestep = 0; } void tearDown() { m_Surface = nullptr; m_CloneSurface = nullptr; - m_SphereSource = nullptr; } void InitializationSurfacePointer_Success() { CPPUNIT_ASSERT_MESSAGE("Testing initialization", m_Surface.GetPointer()); } void InitializationCloneSurfacePointer_Success() { CPPUNIT_ASSERT_MESSAGE("Testing clone surface initialization", m_CloneSurface.GetPointer()); } void StateOfVtkPolyDataEqualNullPointer_Success() { CPPUNIT_ASSERT_MESSAGE("Testing initial state of vtkPolyData", m_Surface->GetVtkPolyData() == nullptr); } void SetVtkPolyDataNotNullPointer_Failure() { - vtkPolyData *polys = m_SphereSource->GetOutput(); + vtkSmartPointer polys = m_SphereSource->GetOutput(); m_Surface->SetVtkPolyData(polys); - m_SphereSource->Delete(); CPPUNIT_ASSERT_MESSAGE("Testing set vtkPolyData", m_Surface->GetVtkPolyData() != nullptr); } void SetClonedVtkPolyDataNotNullPointer_Failure() { - vtkPolyData *polys = m_SphereSource->GetOutput(); + vtkSmartPointer polys = m_SphereSource->GetOutput(); m_Surface->SetVtkPolyData(polys); - m_SphereSource->Delete(); m_CloneSurface = m_Surface->Clone(); CPPUNIT_ASSERT_MESSAGE("Testing set vtkPolyData of cloned surface!", m_CloneSurface->GetVtkPolyData() != nullptr); } void GetBoundingBox_Success() { - vtkPolyData *polys = m_SphereSource->GetOutput(); + vtkSmartPointer polys = m_SphereSource->GetOutput(); m_Surface->SetVtkPolyData(polys); - m_SphereSource->Delete(); double bounds[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; polys->ComputeBounds(); polys->GetBounds(bounds); m_Surface->UpdateOutputInformation(); m_Surface->SetRequestedRegionToLargestPossibleRegion(); auto *bb = const_cast(m_Surface->GetGeometry()->GetBoundingBox()); mitk::BoundingBox::BoundsArrayType surfBounds = bb->GetBounds(); bool passed = false; if (bounds[0] == surfBounds[0] && bounds[1] == surfBounds[1] && bounds[2] == surfBounds[2] && bounds[3] == surfBounds[3] && bounds[4] == surfBounds[4] && bounds[5] == surfBounds[5]) { passed = true; } CPPUNIT_ASSERT_MESSAGE("Testing GetBoundingBox()", passed); } void SurfaceExpandTimestepsAreFive_Success() { m_Surface->Expand(5); m_Surface->Update(); m_Surface->SetRequestedRegionToLargestPossibleRegion(); mitk::Surface::RegionType requestedRegion = m_Surface->GetRequestedRegion(); CPPUNIT_ASSERT_MESSAGE("Testing mitk::Surface::Expand( timesteps ): ", requestedRegion.GetSize(3) == 5); } void Surface4DDataCreation_Success() { double boundsMat[5][6]; for (int i = 0; i < 5; i++) { - vtkSphereSource *sphereSource = vtkSphereSource::New(); + vtkNew sphereSource; sphereSource->SetCenter(0, 0, 0); sphereSource->SetRadius(1.0 * (i + 1.0)); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); sphereSource->GetOutput()->ComputeBounds(); sphereSource->GetOutput()->GetBounds(boundsMat[i]); m_Surface->SetVtkPolyData(sphereSource->GetOutput(), i); - sphereSource->Delete(); } m_Surface->UpdateOutputInformation(); m_Surface->SetRequestedRegionToLargestPossibleRegion(); bool passed = true; for (int i = 0; i < 5; i++) { mitk::BoundingBox::BoundsArrayType surfBounds = (const_cast(m_Surface->GetTimeGeometry()->GetGeometryForTimeStep(i)->GetBoundingBox())) ->GetBounds(); if (boundsMat[i][0] != surfBounds[0] || boundsMat[i][1] != surfBounds[1] || boundsMat[i][2] != surfBounds[2] || boundsMat[i][3] != surfBounds[3] || boundsMat[i][4] != surfBounds[4] || boundsMat[i][5] != surfBounds[5]) { passed = false; break; } } CPPUNIT_ASSERT_MESSAGE("Testing mitk::Surface::Testing 4D surface data creation", passed); } void TimeGeometrySurface_Success() { m_Timestep = m_InputTimeGeometry->TimePointToTimeStep(m_Time); CPPUNIT_ASSERT_MESSAGE("Testing correctness of geometry for surface->GetUpdatedTimeGeometry()", m_Time == m_Timestep); } void ChangingDataOfSpecificTimestepSurface_Success() { - vtkSphereSource *sphereSource = vtkSphereSource::New(); + vtkNew sphereSource; sphereSource->SetCenter(0, 0, 0); sphereSource->SetRadius(100.0); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); m_Surface->SetVtkPolyData(sphereSource->GetOutput(), 3); - sphereSource->Delete(); m_Timestep = m_InputTimeGeometry->TimePointToTimeStep(m_Time); CPPUNIT_ASSERT_MESSAGE( "Explicitly changing the data of timestep 3 and checking for timebounds correctness of surface's geometry again", m_Time == m_Timestep); } void SurfaceCopyWithGraft_Failure() { double boundsMat[5][6]; for (int i = 0; i < 5; i++) { - vtkSphereSource *sphereSource = vtkSphereSource::New(); + vtkNew sphereSource; sphereSource->SetCenter(0, 0, 0); sphereSource->SetRadius(1.0 * (i + 1.0)); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); sphereSource->GetOutput()->ComputeBounds(); sphereSource->GetOutput()->GetBounds(boundsMat[i]); m_Surface->SetVtkPolyData(sphereSource->GetOutput(), i); - sphereSource->Delete(); } m_Surface->UpdateOutputInformation(); m_Surface->SetRequestedRegionToLargestPossibleRegion(); mitk::Surface::Pointer dummy = mitk::Surface::New(); dummy->Graft(m_Surface); CPPUNIT_ASSERT_MESSAGE("Testing copying a Surface with Graft()", dummy->GetVtkPolyData() != nullptr); } void CopyingNumberOfTimesteps_Success() { double boundsMat[5][6]; for (int i = 0; i < 5; i++) { - vtkSphereSource *sphereSource = vtkSphereSource::New(); + vtkNew sphereSource; sphereSource->SetCenter(0, 0, 0); sphereSource->SetRadius(1.0 * (i + 1.0)); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); sphereSource->GetOutput()->ComputeBounds(); sphereSource->GetOutput()->GetBounds(boundsMat[i]); m_Surface->SetVtkPolyData(sphereSource->GetOutput(), i); - sphereSource->Delete(); } m_Surface->UpdateOutputInformation(); m_Surface->SetRequestedRegionToLargestPossibleRegion(); unsigned int numberoftimesteps = m_Surface->GetTimeSteps(); mitk::Surface::Pointer dummy = mitk::Surface::New(); dummy->Graft(m_Surface); CPPUNIT_ASSERT_MESSAGE(" Old timesteps == copy of timesteps ", dummy->GetTimeSteps() == numberoftimesteps); } void DestructionOfSurface_Success() { m_Surface = nullptr; CPPUNIT_ASSERT_MESSAGE("Testing destruction of surface", m_Surface.IsNull()); } }; MITK_TEST_SUITE_REGISTRATION(mitkSurface) diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Rendering/mitkOdfVtkMapper2D.txx b/Modules/DiffusionImaging/DiffusionCore/include/Rendering/mitkOdfVtkMapper2D.txx index c2f796c13a..6e06fd997c 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Rendering/mitkOdfVtkMapper2D.txx +++ b/Modules/DiffusionImaging/DiffusionCore/include/Rendering/mitkOdfVtkMapper2D.txx @@ -1,984 +1,984 @@ /*=================================================================== 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 __mitkOdfVtkMapper2D_txx__ #define __mitkOdfVtkMapper2D_txx__ #include "mitkOdfVtkMapper2D.h" #include "mitkDataNode.h" #include "mitkBaseRenderer.h" #include "mitkMatrixConvert.h" #include "mitkGeometry3D.h" #include "mitkTimeGeometry.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include "mitkProperties.h" #include "mitkTensorImage.h" #include "mitkShImage.h" #include "vtkSphereSource.h" #include "vtkPropCollection.h" #include "vtkMaskedGlyph3D.h" #include "vtkGlyph2D.h" #include "vtkGlyph3D.h" #include "vtkMaskedProgrammableGlyphFilter.h" #include "vtkImageData.h" #include "vtkLinearTransform.h" #include "vtkCamera.h" #include "vtkPointData.h" #include "vtkTransformPolyDataFilter.h" #include "vtkTransform.h" #include "vtkOdfSource.h" #include "vtkDoubleArray.h" #include "vtkLookupTable.h" #include "vtkProperty.h" #include "vtkPolyDataNormals.h" #include "vtkLight.h" #include "vtkLightCollection.h" #include "vtkMath.h" #include "vtkFloatArray.h" #include "vtkDelaunay2D.h" #include "vtkMapper.h" #include #include #include "vtkRenderer.h" #include "itkOrientationDistributionFunction.h" #include "itkFixedArray.h" #include #include "vtkOpenGLRenderer.h" #define _USE_MATH_DEFINES #include #include template vtkSmartPointer mitk::OdfVtkMapper2D::m_OdfTransform = vtkSmartPointer::New(); template vtkSmartPointer mitk::OdfVtkMapper2D::m_OdfSource = vtkSmartPointer::New(); template float mitk::OdfVtkMapper2D::m_Scaling; template int mitk::OdfVtkMapper2D::m_Normalization; template int mitk::OdfVtkMapper2D::m_ScaleBy; template float mitk::OdfVtkMapper2D::m_IndexParam1; template float mitk::OdfVtkMapper2D::m_IndexParam2; template bool mitk::OdfVtkMapper2D::m_ToggleTensorEllipsoidView = false; template bool mitk::OdfVtkMapper2D::m_ToggleColourisationMode = false; template bool mitk::OdfVtkMapper2D::m_ToggleGlyphPlacementMode = true; template vtkSmartPointer mitk::OdfVtkMapper2D::m_ColourScalars = nullptr; template vnl_matrix mitk::OdfVtkMapper2D::m_Sh2Basis = mitk::sh::CalcShBasisForDirections(2, itk::PointShell >::DistributePointShell()->as_matrix()); template vnl_matrix mitk::OdfVtkMapper2D::m_Sh4Basis = mitk::sh::CalcShBasisForDirections(4, itk::PointShell >::DistributePointShell()->as_matrix()); template vnl_matrix mitk::OdfVtkMapper2D::m_Sh6Basis = mitk::sh::CalcShBasisForDirections(6, itk::PointShell >::DistributePointShell()->as_matrix()); template vnl_matrix mitk::OdfVtkMapper2D::m_Sh8Basis = mitk::sh::CalcShBasisForDirections(8, itk::PointShell >::DistributePointShell()->as_matrix()); template vnl_matrix mitk::OdfVtkMapper2D::m_Sh10Basis = mitk::sh::CalcShBasisForDirections(10, itk::PointShell >::DistributePointShell()->as_matrix()); template vnl_matrix mitk::OdfVtkMapper2D::m_Sh12Basis = mitk::sh::CalcShBasisForDirections(12, itk::PointShell >::DistributePointShell()->as_matrix()); template mitk::OdfVtkMapper2D::LocalStorage::LocalStorage() { m_PropAssemblies.push_back(vtkPropAssembly::New()); m_PropAssemblies.push_back(vtkPropAssembly::New()); m_PropAssemblies.push_back(vtkPropAssembly::New()); m_OdfsPlanes.push_back(vtkAppendPolyData::New()); m_OdfsPlanes.push_back(vtkAppendPolyData::New()); m_OdfsPlanes.push_back(vtkAppendPolyData::New()); m_OdfsPlanes[0]->AddInputData(vtkPolyData::New()); m_OdfsPlanes[1]->AddInputData(vtkPolyData::New()); m_OdfsPlanes[2]->AddInputData(vtkPolyData::New()); m_OdfsActors.push_back(vtkActor::New()); m_OdfsActors.push_back(vtkActor::New()); m_OdfsActors.push_back(vtkActor::New()); m_OdfsActors[0]->GetProperty()->SetInterpolationToGouraud(); m_OdfsActors[1]->GetProperty()->SetInterpolationToGouraud(); m_OdfsActors[2]->GetProperty()->SetInterpolationToGouraud(); m_OdfsMappers.push_back(vtkPolyDataMapper::New()); m_OdfsMappers.push_back(vtkPolyDataMapper::New()); m_OdfsMappers.push_back(vtkPolyDataMapper::New()); - vtkLookupTable *lut = vtkLookupTable::New(); + vtkSmartPointer lut = vtkSmartPointer::New(); m_OdfsMappers[0]->SetLookupTable(lut); m_OdfsMappers[1]->SetLookupTable(lut); m_OdfsMappers[2]->SetLookupTable(lut); m_OdfsActors[0]->SetMapper(m_OdfsMappers[0]); m_OdfsActors[1]->SetMapper(m_OdfsMappers[1]); m_OdfsActors[2]->SetMapper(m_OdfsMappers[2]); } template mitk::OdfVtkMapper2D ::OdfVtkMapper2D() { m_LastDisplayGeometry.push_back(OdfDisplayGeometry()); m_LastDisplayGeometry.push_back(OdfDisplayGeometry()); m_LastDisplayGeometry.push_back(OdfDisplayGeometry()); m_Planes.push_back(vtkPlane::New()); m_Planes.push_back(vtkPlane::New()); m_Planes.push_back(vtkPlane::New()); m_Cutters.push_back(vtkCutter::New()); m_Cutters.push_back(vtkCutter::New()); m_Cutters.push_back(vtkCutter::New()); m_Cutters[0]->SetCutFunction( m_Planes[0] ); m_Cutters[0]->GenerateValues( 1, 0, 1 ); m_Cutters[1]->SetCutFunction( m_Planes[1] ); m_Cutters[1]->GenerateValues( 1, 0, 1 ); m_Cutters[2]->SetCutFunction( m_Planes[2] ); m_Cutters[2]->GenerateValues( 1, 0, 1 ); // Windowing the cutted planes in direction 1 m_ThickPlanes1.push_back(vtkThickPlane::New()); m_ThickPlanes1.push_back(vtkThickPlane::New()); m_ThickPlanes1.push_back(vtkThickPlane::New()); m_Clippers1.push_back(vtkClipPolyData::New()); m_Clippers1.push_back(vtkClipPolyData::New()); m_Clippers1.push_back(vtkClipPolyData::New()); m_Clippers1[0]->SetClipFunction( m_ThickPlanes1[0] ); m_Clippers1[1]->SetClipFunction( m_ThickPlanes1[1] ); m_Clippers1[2]->SetClipFunction( m_ThickPlanes1[2] ); // Windowing the cutted planes in direction 2 m_ThickPlanes2.push_back(vtkThickPlane::New()); m_ThickPlanes2.push_back(vtkThickPlane::New()); m_ThickPlanes2.push_back(vtkThickPlane::New()); m_Clippers2.push_back(vtkClipPolyData::New()); m_Clippers2.push_back(vtkClipPolyData::New()); m_Clippers2.push_back(vtkClipPolyData::New()); m_Clippers2[0]->SetClipFunction( m_ThickPlanes2[0] ); m_Clippers2[1]->SetClipFunction( m_ThickPlanes2[1] ); m_Clippers2[2]->SetClipFunction( m_ThickPlanes2[2] ); m_ShowMaxNumber = 500; } template mitk::OdfVtkMapper2D ::~OdfVtkMapper2D() { } template mitk::Image* mitk::OdfVtkMapper2D ::GetInput() { return static_cast ( m_DataNode->GetData() ); } template vtkProp* mitk::OdfVtkMapper2D ::GetVtkProp(mitk::BaseRenderer* renderer) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); return localStorage->m_PropAssemblies[GetIndex(renderer)]; } template int mitk::OdfVtkMapper2D ::GetIndex(mitk::BaseRenderer* renderer) { if(!strcmp(renderer->GetName(),"stdmulti.widget1")) return 0; if(!strcmp(renderer->GetName(),"stdmulti.widget2")) return 1; if(!strcmp(renderer->GetName(),"stdmulti.widget3")) return 2; return 0; } template void mitk::OdfVtkMapper2D ::GlyphMethod(void *arg) { vtkMaskedProgrammableGlyphFilter* pfilter=(vtkMaskedProgrammableGlyphFilter*)arg; double point[3]; double debugpoint[3]; pfilter->GetPoint(point); pfilter->GetPoint(debugpoint); itk::Point p(point); Vector3D spacing = pfilter->GetGeometry()->GetSpacing(); p[0] /= spacing[0]; p[1] /= spacing[1]; p[2] /= spacing[2]; mitk::Point3D p2; pfilter->GetGeometry()->IndexToWorld( p, p2 ); point[0] = p2[0]; point[1] = p2[1]; point[2] = p2[2]; vtkPointData* data = pfilter->GetPointData(); vtkDataArray* image_vals = data->GetArray("vector"); vtkIdType id = pfilter->GetPointId(); m_OdfTransform->Identity(); m_OdfTransform->Translate(point[0],point[1],point[2]); typedef itk::OrientationDistributionFunction OdfType; OdfType odf; if( image_vals->GetNumberOfComponents()==6 && !m_ToggleTensorEllipsoidView ) { float tensorelems[6] = { (float)image_vals->GetComponent(id,0), (float)image_vals->GetComponent(id,1), (float)image_vals->GetComponent(id,2), (float)image_vals->GetComponent(id,3), (float)image_vals->GetComponent(id,4), (float)image_vals->GetComponent(id,5), }; itk::DiffusionTensor3D tensor(tensorelems); odf.InitFromTensor(tensor); } else if( image_vals->GetNumberOfComponents()==6 && m_ToggleTensorEllipsoidView ) { float tensorelems[6] = { (float)image_vals->GetComponent(id,0), (float)image_vals->GetComponent(id,1), (float)image_vals->GetComponent(id,2), (float)image_vals->GetComponent(id,3), (float)image_vals->GetComponent(id,4), (float)image_vals->GetComponent(id,5), }; itk::DiffusionTensor3D tensor( tensorelems ); odf.InitFromEllipsoid( tensor ); } else if (image_vals->GetNumberOfComponents() == ODF_SAMPLING_SIZE) { for(int i=0; iGetComponent(id,i); } else { int nrCoeffs = image_vals->GetNumberOfComponents(); Vector< float, N > odf_vals; vnl_vector< float > coeffs(nrCoeffs); for(int i=0; iGetComponent(id,i); switch (nrCoeffs) { case 6: odf_vals = ( m_Sh2Basis * coeffs ).data_block(); break; case 15: odf_vals = ( m_Sh4Basis * coeffs ).data_block(); break; case 28: odf_vals = ( m_Sh6Basis * coeffs ).data_block(); break; case 45: odf_vals = ( m_Sh8Basis * coeffs ).data_block(); break; case 66: odf_vals = ( m_Sh10Basis * coeffs ).data_block(); break; case 91: odf_vals = ( m_Sh12Basis * coeffs ).data_block(); break; default : mitkThrow() << "SH order larger 12 not supported in current ODF mapper version"; } for(int i=0; iSetUseCustomColor(true); vnl_vector_fixed d = odf.GetPrincipalDiffusionDirection(); m_OdfSource->SetColor(fabs(d[0])*255,fabs(d[1])*255,fabs(d[2])*255); } else { m_OdfSource->SetUseCustomColor(false); } switch(m_ScaleBy) { case ODFSB_NONE: m_OdfSource->SetScale(m_Scaling); break; case ODFSB_GFA: m_OdfSource->SetScale(m_Scaling*odf.GetGeneralizedFractionalAnisotropy()); break; case ODFSB_PC: m_OdfSource->SetScale(m_Scaling*odf.GetPrincipleCurvature(m_IndexParam1, m_IndexParam2, 0)); break; } m_OdfSource->SetNormalization(m_Normalization); m_OdfSource->SetOdf(odf); m_OdfSource->Modified(); } template typename mitk::OdfVtkMapper2D::OdfDisplayGeometry mitk::OdfVtkMapper2D ::MeasureDisplayedGeometry(mitk::BaseRenderer* renderer) { PlaneGeometry::ConstPointer worldPlaneGeometry = renderer->GetCurrentWorldPlaneGeometry(); // set up the cutter orientation according to the current geometry of // the renderers plane double vp[ 3 ], vnormal[ 3 ]; Point3D point = worldPlaneGeometry->GetOrigin(); Vector3D normal = worldPlaneGeometry->GetNormal(); normal.Normalize(); vnl2vtk( point.GetVnlVector(), vp ); vnl2vtk( normal.GetVnlVector(), vnormal ); Point2D dispSizeInMM = renderer->GetViewportSizeInMM(); Point2D displayGeometryOriginInMM = renderer->GetOriginInMM(); mitk::Vector2D size = dispSizeInMM.GetVectorFromOrigin(); mitk::Vector2D origin = displayGeometryOriginInMM.GetVectorFromOrigin(); // // |------O------| // | d2 | // L d1 M | // | | // |-------------| // mitk::Vector2D M; mitk::Vector2D L; mitk::Vector2D O; M[0] = origin[0] + size[0]/2; M[1] = origin[1] + size[1]/2; L[0] = origin[0]; L[1] = origin[1] + size[1]/2; O[0] = origin[0] + size[0]/2; O[1] = origin[1] + size[1]; mitk::Point2D point1; point1[0] = M[0]; point1[1] = M[1]; mitk::Point3D M3D; renderer->GetCurrentWorldPlaneGeometry()->Map(point1, M3D); point1[0] = L[0]; point1[1] = L[1]; mitk::Point3D L3D; renderer->GetCurrentWorldPlaneGeometry()->Map(point1, L3D); point1[0] = O[0]; point1[1] = O[1]; mitk::Point3D O3D; renderer->GetCurrentWorldPlaneGeometry()->Map(point1, O3D); double d1 = sqrt((M3D[0]-L3D[0])*(M3D[0]-L3D[0]) + (M3D[1]-L3D[1])*(M3D[1]-L3D[1]) + (M3D[2]-L3D[2])*(M3D[2]-L3D[2])); double d2 = sqrt((M3D[0]-O3D[0])*(M3D[0]-O3D[0]) + (M3D[1]-O3D[1])*(M3D[1]-O3D[1]) + (M3D[2]-O3D[2])*(M3D[2]-O3D[2])); double d = d1>d2 ? d1 : d2; d = d2; OdfDisplayGeometry retval; retval.vp[0] = vp[0]; retval.vp[1] = vp[1]; retval.vp[2] = vp[2]; retval.vnormal[0] = vnormal[0]; retval.vnormal[1] = vnormal[1]; retval.vnormal[2] = vnormal[2]; retval.normal[0] = normal[0]; retval.normal[1] = normal[1]; retval.normal[2] = normal[2]; retval.d = d; retval.d1 = d1; retval.d2 = d2; retval.M3D[0] = M3D[0]; retval.M3D[1] = M3D[1]; retval.M3D[2] = M3D[2]; retval.L3D[0] = L3D[0]; retval.L3D[1] = L3D[1]; retval.L3D[2] = L3D[2]; retval.O3D[0] = O3D[0]; retval.O3D[1] = O3D[1]; retval.O3D[2] = O3D[2]; retval.vp_original[0] = vp[0]; retval.vp_original[1] = vp[1]; retval.vp_original[2] = vp[2]; retval.vnormal_original[0] = vnormal[0]; retval.vnormal_original[1] = vnormal[1]; retval.vnormal_original[2] = vnormal[2]; retval.size[0] = size[0]; retval.size[1] = size[1]; retval.origin[0] = origin[0]; retval.origin[1] = origin[1]; return retval; } template void mitk::OdfVtkMapper2D ::Slice(mitk::BaseRenderer* renderer, OdfDisplayGeometry dispGeo) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); vtkLinearTransform * vtktransform = this->GetDataNode()->GetVtkTransform(this->GetTimestep()); int index = GetIndex(renderer); vtkSmartPointer inversetransform = vtkSmartPointer::New(); inversetransform->Identity(); inversetransform->Concatenate(vtktransform->GetLinearInverse()); double myscale[3]; ((vtkTransform*)vtktransform)->GetScale(myscale); myscale[0] = fabs(myscale[0]); myscale[1] = fabs(myscale[1]); myscale[2] = fabs(myscale[2]); inversetransform->PostMultiply(); inversetransform->Scale(myscale[0],myscale[1],myscale[2]); inversetransform->TransformPoint( dispGeo.vp, dispGeo.vp ); inversetransform->TransformNormalAtPoint( dispGeo.vp, dispGeo.vnormal, dispGeo.vnormal ); // vtk works in axis align coords // thus the normal also must be axis align, since // we do not allow arbitrary cutting through volume // // vnormal should already be axis align, but in order // to get rid of precision effects, we set the two smaller // components to zero here int dims[3]; m_VtkImage->GetDimensions(dims); double spac[3]; m_VtkImage->GetSpacing(spac); if(fabs(dispGeo.vnormal[0]) > fabs(dispGeo.vnormal[1]) && fabs(dispGeo.vnormal[0]) > fabs(dispGeo.vnormal[2]) ) { if(fabs(dispGeo.vp[0]/spac[0]) < 0.4) dispGeo.vp[0] = 0.4*spac[0]; if(fabs(dispGeo.vp[0]/spac[0]) > (dims[0]-1)-0.4) dispGeo.vp[0] = ((dims[0]-1)-0.4)*spac[0]; dispGeo.vnormal[1] = 0; dispGeo.vnormal[2] = 0; } if(fabs(dispGeo.vnormal[1]) > fabs(dispGeo.vnormal[0]) && fabs(dispGeo.vnormal[1]) > fabs(dispGeo.vnormal[2]) ) { if(fabs(dispGeo.vp[1]/spac[1]) < 0.4) dispGeo.vp[1] = 0.4*spac[1]; if(fabs(dispGeo.vp[1]/spac[1]) > (dims[1]-1)-0.4) dispGeo.vp[1] = ((dims[1]-1)-0.4)*spac[1]; dispGeo.vnormal[0] = 0; dispGeo.vnormal[2] = 0; } if(fabs(dispGeo.vnormal[2]) > fabs(dispGeo.vnormal[1]) && fabs(dispGeo.vnormal[2]) > fabs(dispGeo.vnormal[0]) ) { if(fabs(dispGeo.vp[2]/spac[2]) < 0.4) dispGeo.vp[2] = 0.4*spac[2]; if(fabs(dispGeo.vp[2]/spac[2]) > (dims[2]-1)-0.4) dispGeo.vp[2] = ((dims[2]-1)-0.4)*spac[2]; dispGeo.vnormal[0] = 0; dispGeo.vnormal[1] = 0; } m_Planes[index]->SetTransform( (vtkAbstractTransform*)nullptr ); m_Planes[index]->SetOrigin( dispGeo.vp ); m_Planes[index]->SetNormal( dispGeo.vnormal ); vtkSmartPointer points; vtkSmartPointer tmppoints; vtkSmartPointer polydata; vtkSmartPointer pointdata; vtkSmartPointer delaunay; vtkSmartPointer cuttedPlane; // the cutter only works if we do not have a 2D-image // or if we have a 2D-image and want to see the whole image. // // for side views of 2D-images, we need some special treatment if(!( (dims[0] == 1 && dispGeo.vnormal[0] != 0) || (dims[1] == 1 && dispGeo.vnormal[1] != 0) || (dims[2] == 1 && dispGeo.vnormal[2] != 0) )) { m_Cutters[index]->SetCutFunction( m_Planes[index] ); m_Cutters[index]->SetInputData( m_VtkImage ); m_Cutters[index]->Update(); cuttedPlane = m_Cutters[index]->GetOutput(); } else { // cutting of a 2D-Volume does not work, // so we have to build up our own polydata object cuttedPlane = vtkPolyData::New(); points = vtkPoints::New(); points->SetNumberOfPoints(m_VtkImage->GetNumberOfPoints()); for(int i=0; iGetNumberOfPoints(); i++) { points->SetPoint(i, m_VtkImage->GetPoint(i)); } cuttedPlane->SetPoints(points); int nZero1, nZero2; if(dims[0]==1) { nZero1 = 1; nZero2 = 2; } else if(dims[1]==1) { nZero1 = 0; nZero2 = 2; } else { nZero1 = 0; nZero2 = 1; } tmppoints = vtkPoints::New(); for(int j=0; jGetNumberOfPoints(); j++){ double pt[3]; m_VtkImage->GetPoint(j,pt); tmppoints->InsertNextPoint(pt[nZero1],pt[nZero2],0); } polydata = vtkPolyData::New(); polydata->SetPoints( tmppoints ); delaunay = vtkDelaunay2D::New(); delaunay->SetInputData( polydata ); delaunay->Update(); vtkCellArray* polys = delaunay->GetOutput()->GetPolys(); cuttedPlane->SetPolys(polys); } if(cuttedPlane->GetNumberOfPoints()) { // WINDOWING HERE dispGeo.vnormal[0] = dispGeo.M3D[0]-dispGeo.O3D[0]; dispGeo.vnormal[1] = dispGeo.M3D[1]-dispGeo.O3D[1]; dispGeo.vnormal[2] = dispGeo.M3D[2]-dispGeo.O3D[2]; vtkMath::Normalize(dispGeo.vnormal); dispGeo.vp[0] = dispGeo.M3D[0]; dispGeo.vp[1] = dispGeo.M3D[1]; dispGeo.vp[2] = dispGeo.M3D[2]; inversetransform->TransformPoint( dispGeo.vp, dispGeo.vp ); inversetransform->TransformNormalAtPoint( dispGeo.vp, dispGeo.vnormal, dispGeo.vnormal ); m_ThickPlanes1[index]->count = 0; m_ThickPlanes1[index]->SetTransform((vtkAbstractTransform*)nullptr ); m_ThickPlanes1[index]->SetPose( dispGeo.vnormal, dispGeo.vp ); m_ThickPlanes1[index]->SetThickness(dispGeo.d2); m_Clippers1[index]->SetClipFunction( m_ThickPlanes1[index] ); m_Clippers1[index]->SetInputData( cuttedPlane ); m_Clippers1[index]->SetInsideOut(1); m_Clippers1[index]->Update(); dispGeo.vnormal[0] = dispGeo.M3D[0]-dispGeo.L3D[0]; dispGeo.vnormal[1] = dispGeo.M3D[1]-dispGeo.L3D[1]; dispGeo.vnormal[2] = dispGeo.M3D[2]-dispGeo.L3D[2]; vtkMath::Normalize(dispGeo.vnormal); dispGeo.vp[0] = dispGeo.M3D[0]; dispGeo.vp[1] = dispGeo.M3D[1]; dispGeo.vp[2] = dispGeo.M3D[2]; inversetransform->TransformPoint( dispGeo.vp, dispGeo.vp ); inversetransform->TransformNormalAtPoint( dispGeo.vp, dispGeo.vnormal, dispGeo.vnormal ); m_ThickPlanes2[index]->count = 0; m_ThickPlanes2[index]->SetTransform((vtkAbstractTransform*)nullptr ); m_ThickPlanes2[index]->SetPose( dispGeo.vnormal, dispGeo.vp ); m_ThickPlanes2[index]->SetThickness(dispGeo.d1); m_Clippers2[index]->SetClipFunction( m_ThickPlanes2[index] ); m_Clippers2[index]->SetInputData( m_Clippers1[index]->GetOutput() ); m_Clippers2[index]->SetInsideOut(1); m_Clippers2[index]->Update(); cuttedPlane = m_Clippers2[index]->GetOutput (); if(cuttedPlane->GetNumberOfPoints()) { localStorage->m_OdfsPlanes[index]->RemoveAllInputs(); vtkSmartPointer normals = vtkSmartPointer::New(); normals->SetInputConnection( m_OdfSource->GetOutputPort() ); normals->SplittingOff(); normals->ConsistencyOff(); normals->AutoOrientNormalsOff(); normals->ComputePointNormalsOn(); normals->ComputeCellNormalsOff(); normals->FlipNormalsOff(); normals->NonManifoldTraversalOff(); vtkSmartPointer trans = vtkSmartPointer::New(); trans->SetInputConnection( normals->GetOutputPort() ); trans->SetTransform(m_OdfTransform); vtkSmartPointer glyphGenerator = vtkSmartPointer::New(); glyphGenerator->SetMaximumNumberOfPoints(std::min(m_ShowMaxNumber,(int)cuttedPlane->GetNumberOfPoints())); glyphGenerator->SetRandomMode( m_ToggleGlyphPlacementMode ); glyphGenerator->SetUseMaskPoints(1); glyphGenerator->SetSourceConnection(trans->GetOutputPort() ); glyphGenerator->SetInput(cuttedPlane); glyphGenerator->SetColorModeToColorBySource(); glyphGenerator->SetGeometry(this->GetDataNode()->GetData()->GetGeometry()); glyphGenerator->SetGlyphMethod(&(GlyphMethod),(void *)glyphGenerator); try { glyphGenerator->Update(); } catch( itk::ExceptionObject& err ) { std::cout << err << std::endl; } localStorage->m_OdfsPlanes[index]->AddInputConnection(glyphGenerator->GetOutputPort()); localStorage->m_OdfsPlanes[index]->Update(); } } localStorage->m_OdfsMappers[index]->ScalarVisibilityOn(); localStorage->m_OdfsMappers[index]->SetScalarModeToUsePointFieldData(); localStorage->m_OdfsMappers[index]->SelectColorArray("ODF_COLORS"); localStorage->m_PropAssemblies[index]->VisibilityOn(); if(localStorage->m_PropAssemblies[index]->GetParts()->IsItemPresent(localStorage->m_OdfsActors[index])) { localStorage->m_PropAssemblies[index]->RemovePart(localStorage->m_OdfsActors[index]); } localStorage->m_OdfsMappers[index]->SetInputData(localStorage->m_OdfsPlanes[index]->GetOutput()); localStorage->m_PropAssemblies[index]->AddPart(localStorage->m_OdfsActors[index]); } template bool mitk::OdfVtkMapper2D ::IsVisibleOdfs(mitk::BaseRenderer* renderer) { mitk::Image::Pointer input = const_cast(this->GetInput()); const TimeGeometry *inputTimeGeometry = input->GetTimeGeometry(); if(inputTimeGeometry==nullptr || inputTimeGeometry->CountTimeSteps()==0 || !inputTimeGeometry->IsValidTimeStep(this->GetTimestep())) return false; if(this->IsPlaneRotated(renderer)) return false; bool retval = false; switch(GetIndex(renderer)) { case 0: GetDataNode()->GetVisibility(retval, renderer, "VisibleOdfs_T"); break; case 1: GetDataNode()->GetVisibility(retval, renderer, "VisibleOdfs_S"); break; case 2: GetDataNode()->GetVisibility(retval, renderer, "VisibleOdfs_C"); break; } return retval; } template void mitk::OdfVtkMapper2D ::MitkRenderOverlay(mitk::BaseRenderer* renderer) { if ( this->IsVisibleOdfs(renderer)==false ) return; if ( this->GetVtkProp(renderer)->GetVisibility() ) this->GetVtkProp(renderer)->RenderOverlay(renderer->GetVtkRenderer()); } template void mitk::OdfVtkMapper2D ::MitkRenderOpaqueGeometry(mitk::BaseRenderer* renderer) { if ( this->IsVisibleOdfs( renderer )==false ) return; if ( this->GetVtkProp(renderer)->GetVisibility() ) { // adapt cam pos this->GetVtkProp(renderer)->RenderOpaqueGeometry( renderer->GetVtkRenderer() ); } } template void mitk::OdfVtkMapper2D ::MitkRenderTranslucentGeometry(mitk::BaseRenderer* renderer) { if ( this->IsVisibleOdfs(renderer)==false ) return; if ( this->GetVtkProp(renderer)->GetVisibility() ) this->GetVtkProp(renderer)->RenderTranslucentPolygonalGeometry(renderer->GetVtkRenderer()); } template void mitk::OdfVtkMapper2D ::Update(mitk::BaseRenderer* renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; mitk::Image::Pointer input = const_cast( this->GetInput() ); if ( input.IsNull() ) return ; std::string classname("TensorImage"); if(classname.compare(input->GetNameOfClass())==0) m_VtkImage = dynamic_cast( this->GetInput() )->GetNonRgbVtkImageData(); std::string qclassname("OdfImage"); if(qclassname.compare(input->GetNameOfClass())==0) m_VtkImage = dynamic_cast( this->GetInput() )->GetNonRgbVtkImageData(); std::string shclassname("ShImage"); if(shclassname.compare(input->GetNameOfClass())==0) m_VtkImage = dynamic_cast( this->GetInput() )->GetNonRgbVtkImageData(); if( m_VtkImage ) { // make sure, that we have point data with more than 1 component (as vectors) vtkPointData* pointData = m_VtkImage->GetPointData(); if ( pointData == nullptr ) { itkWarningMacro( << "m_VtkImage->GetPointData() returns NULL!" ); return ; } if ( pointData->GetNumberOfArrays() == 0 ) { itkWarningMacro( << "m_VtkImage->GetPointData()->GetNumberOfArrays() is 0!" ); return ; } else if ( pointData->GetArrayName( 0 ) == nullptr ) { m_VtkImage->GetPointData()->GetArray(0)->SetName("vector"); } GenerateDataForRenderer(renderer); } else { itkWarningMacro( << "m_VtkImage is NULL!" ); return ; } } template void mitk::OdfVtkMapper2D ::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); OdfDisplayGeometry dispGeo = MeasureDisplayedGeometry( renderer); if ((localStorage->m_LastUpdateTime >= m_DataNode->GetMTime()) //was the node modified? && (localStorage->m_LastUpdateTime >= m_DataNode->GetPropertyList()->GetMTime()) //was a property modified? && (localStorage->m_LastUpdateTime >= m_DataNode->GetPropertyList(renderer)->GetMTime()) && dispGeo.Equals(m_LastDisplayGeometry.at(GetIndex(renderer)))) { return; } localStorage->m_LastUpdateTime.Modified(); if(!IsVisibleOdfs(renderer)) { localStorage->m_OdfsActors[0]->VisibilityOff(); localStorage->m_OdfsActors[1]->VisibilityOff(); localStorage->m_OdfsActors[2]->VisibilityOff(); } else { localStorage->m_OdfsActors[0]->VisibilityOn(); localStorage->m_OdfsActors[1]->VisibilityOn(); localStorage->m_OdfsActors[2]->VisibilityOn(); m_OdfSource->SetAdditionalScale(GetMinImageSpacing(GetIndex(renderer))); ApplyPropertySettings(); Slice(renderer, dispGeo); m_LastDisplayGeometry[GetIndex(renderer)] = dispGeo; } } template double mitk::OdfVtkMapper2D::GetMinImageSpacing( int index ) { // Spacing adapted scaling double spacing[3]; m_VtkImage->GetSpacing(spacing); double min = spacing[0]; if(index==0) { min = spacing[0]; min = min > spacing[1] ? spacing[1] : min; } if(index==1) { min = spacing[1]; min = min > spacing[2] ? spacing[2] : min; } if(index==2) { min = spacing[0]; min = min > spacing[2] ? spacing[2] : min; } return min; } template void mitk::OdfVtkMapper2D ::ApplyPropertySettings() { this->GetDataNode()->GetFloatProperty( "Scaling", m_Scaling ); this->GetDataNode()->GetIntProperty( "ShowMaxNumber", m_ShowMaxNumber ); OdfNormalizationMethodProperty* nmp = dynamic_cast(this->GetDataNode()->GetProperty( "Normalization" )); if(nmp) m_Normalization = nmp->GetNormalization(); OdfScaleByProperty* sbp = dynamic_cast(this->GetDataNode()->GetProperty( "ScaleBy" )); if(sbp) m_ScaleBy = sbp->GetScaleBy(); this->GetDataNode()->GetFloatProperty( "IndexParam1", m_IndexParam1); this->GetDataNode()->GetFloatProperty( "IndexParam2", m_IndexParam2); this->GetDataNode()->GetBoolProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", m_ToggleTensorEllipsoidView ); this->GetDataNode()->GetBoolProperty( "DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", m_ToggleColourisationMode ); this->GetDataNode()->GetBoolProperty( "DiffusionCore.Rendering.OdfVtkMapper.RandomModeBit", m_ToggleGlyphPlacementMode); } template bool mitk::OdfVtkMapper2D ::IsPlaneRotated(mitk::BaseRenderer* renderer) { PlaneGeometry::ConstPointer worldPlaneGeometry = renderer->GetCurrentWorldPlaneGeometry(); double vnormal[ 3 ]; Vector3D normal = worldPlaneGeometry->GetNormal(); normal.Normalize(); vnl2vtk( normal.GetVnlVector(), vnormal ); mitk::Image* currentImage = dynamic_cast( this->GetDataNode()->GetData() ); if( currentImage == nullptr ) return false; mitk::Vector3D imageNormal0 = currentImage->GetSlicedGeometry()->GetAxisVector(0); mitk::Vector3D imageNormal1 = currentImage->GetSlicedGeometry()->GetAxisVector(1); mitk::Vector3D imageNormal2 = currentImage->GetSlicedGeometry()->GetAxisVector(2); imageNormal0.Normalize(); imageNormal1.Normalize(); imageNormal2.Normalize(); double eps = 0.000001; // Did you mean: std::numeric_limits::epsilon(); ? int test = 0; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal0.GetVnlVector()))-1) > eps ) test++; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal1.GetVnlVector()))-1) > eps ) test++; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal2.GetVnlVector()))-1) > eps ) test++; if (test==3) return true; return false; } template void mitk::OdfVtkMapper2D ::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* /*renderer*/, bool /*overwrite*/) { node->SetProperty( "ShowMaxNumber", mitk::IntProperty::New( 500 ) ); node->SetProperty( "Normalization", mitk::OdfNormalizationMethodProperty::New()); mitk::OdfScaleByProperty::Pointer prop = mitk::OdfScaleByProperty::New(); prop->SetScaleByGFA(); node->SetProperty( "ScaleBy", prop); if (dynamic_cast(node->GetData())) { node->AddProperty( "DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", mitk::BoolProperty::New( true ) ); node->SetProperty( "Scaling", mitk::FloatProperty::New( 3.0 ) ); } else { node->AddProperty( "DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", mitk::BoolProperty::New( false ) ); node->SetProperty( "Scaling", mitk::FloatProperty::New( 1.5 ) ); } node->SetProperty( "IndexParam1", mitk::FloatProperty::New(2)); node->SetProperty( "IndexParam2", mitk::FloatProperty::New(1)); node->SetProperty( "visible", mitk::BoolProperty::New( true ) ); node->SetProperty( "VisibleOdfs_T", mitk::BoolProperty::New( false ) ); node->SetProperty( "VisibleOdfs_C", mitk::BoolProperty::New( false ) ); node->SetProperty( "VisibleOdfs_S", mitk::BoolProperty::New( false ) ); node->SetProperty( "layer", mitk::IntProperty::New(100)); node->SetProperty( "DoRefresh", mitk::BoolProperty::New( true ) ); node->AddProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", mitk::BoolProperty::New( true) ); node->AddProperty( "DiffusionCore.Rendering.OdfVtkMapper.RandomModeBit", mitk::BoolProperty::New( true ) ); } #endif // __mitkOdfVtkMapper2D_txx__ diff --git a/Modules/DiffusionImaging/DiffusionIO/files.cmake b/Modules/DiffusionImaging/DiffusionIO/files.cmake index ccf7e79422..7af682f8bc 100644 --- a/Modules/DiffusionImaging/DiffusionIO/files.cmake +++ b/Modules/DiffusionImaging/DiffusionIO/files.cmake @@ -1,41 +1,42 @@ set(CPP_FILES mitkDiffusionModuleActivator.cpp mitkNrrdTbssImageWriterFactory.cpp #mitkFiberBundleIOFactory.cpp mitkConnectomicsNetworkReader.cpp mitkConnectomicsNetworkWriter.cpp mitkConnectomicsNetworkCSVWriter.cpp mitkConnectomicsNetworkMatrixWriter.cpp mitkConnectomicsNetworkSerializer.cpp mitkConnectomicsNetworkDefinitions.cpp mitkNrrdTbssRoiImageIOFactory.cpp #mitkFiberBundleWriterFactory.cpp mitkNrrdTbssRoiImageWriterFactory.cpp mitkFiberTrackingObjectFactory.cpp mitkConnectomicsObjectFactory.cpp mitkQuantificationObjectFactory.cpp mitkNrrdTbssImageIOFactory.cpp mitkDiffusionIOMimeTypes.cpp mitkFiberBundleDicomReader.cpp mitkFiberBundleDicomWriter.cpp mitkFiberBundleTckReader.cpp mitkFiberBundleTrackVisReader.cpp mitkFiberBundleTrackVisWriter.cpp mitkFiberBundleVtkReader.cpp mitkFiberBundleVtkWriter.cpp mitkFiberBundleSerializer.cpp mitkFiberBundleMapper2D.cpp mitkFiberBundleMapper3D.cpp mitkPeakImageMapper2D.cpp + mitkPeakImageMapper3D.cpp mitkTractographyForestReader.cpp mitkTractographyForestWriter.cpp mitkTractographyForestSerializer.cpp mitkPlanarFigureCompositeWriter.cpp mitkPlanarFigureCompositeReader.cpp mitkPlanarFigureCompositeSerializer.cpp ) diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.cpp index f87a75c3da..20907a46a9 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.cpp @@ -1,277 +1,276 @@ /*=================================================================== 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 "mitkFiberBundleMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkDataNode.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class vtkShaderCallback : public vtkCommand { public: static vtkShaderCallback *New() { return new vtkShaderCallback; } mitk::BaseRenderer *renderer; mitk::DataNode *node; void Execute(vtkObject *, unsigned long, void*cbo) override { vtkShaderProgram *program = reinterpret_cast(cbo); float fiberOpacity; bool fiberFading = false; float fiberThickness = 0.0; node->GetOpacity(fiberOpacity, nullptr); node->GetFloatProperty("Fiber2DSliceThickness", fiberThickness); node->GetBoolProperty("Fiber2DfadeEFX", fiberFading); program->SetUniformf("fiberOpacity", fiberOpacity); program->SetUniformi("fiberFadingON", fiberFading); program->SetUniformf("fiberThickness", fiberThickness); if (this->renderer) { //get information about current position of views mitk::SliceNavigationController::Pointer sliceContr = renderer->GetSliceNavigationController(); mitk::PlaneGeometry::ConstPointer planeGeo = sliceContr->GetCurrentPlaneGeometry(); //generate according cutting planes based on the view position float planeNormal[3]; planeNormal[0] = planeGeo->GetNormal()[0]; planeNormal[1] = planeGeo->GetNormal()[1]; planeNormal[2] = planeGeo->GetNormal()[2]; float tmp1 = planeGeo->GetOrigin()[0] * planeNormal[0]; float tmp2 = planeGeo->GetOrigin()[1] * planeNormal[1]; float tmp3 = planeGeo->GetOrigin()[2] * planeNormal[2]; float thickness = tmp1 + tmp2 + tmp3; //attention, correct normalvector - float* a = new float[4]; + float a[4]; for (int i = 0; i < 3; ++i) a[i] = planeNormal[i]; a[3] = thickness; program->SetUniform4f("slicingPlane", a); } } vtkShaderCallback() { this->renderer = nullptr; } }; mitk::FiberBundleMapper2D::FiberBundleMapper2D() : m_LineWidth(1) { - m_lut = vtkLookupTable::New(); + m_lut = vtkSmartPointer::New(); m_lut->Build(); } mitk::FiberBundleMapper2D::~FiberBundleMapper2D() { } mitk::FiberBundle* mitk::FiberBundleMapper2D::GetInput() { return dynamic_cast< mitk::FiberBundle * > ( GetDataNode()->GetData() ); } void mitk::FiberBundleMapper2D::Update(mitk::BaseRenderer * renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; // Calculate time step of the input data for the specified renderer (integer value) // this method is implemented in mitkMapper this->CalculateTimeStep( renderer ); //check if updates occured in the node or on the display FBXLocalStorage *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); //set renderer independent shader properties const DataNode::Pointer node = this->GetDataNode(); float thickness = 2.0; if(!this->GetDataNode()->GetPropertyValue("Fiber2DSliceThickness",thickness)) MITK_INFO << "FIBER2D SLICE THICKNESS PROPERTY ERROR"; bool fiberfading = false; if(!this->GetDataNode()->GetPropertyValue("Fiber2DfadeEFX",fiberfading)) MITK_INFO << "FIBER2D SLICE FADE EFX PROPERTY ERROR"; mitk::FiberBundle* fiberBundle = this->GetInput(); if (fiberBundle==nullptr) return; int lineWidth = 0; node->GetIntProperty("LineWidth", lineWidth); if (m_LineWidth!=lineWidth) { m_LineWidth = lineWidth; fiberBundle->RequestUpdate2D(); } if ( localStorage->m_LastUpdateTimeGetCurrentWorldPlaneGeometryUpdateTime() || localStorage->m_LastUpdateTimeGetUpdateTime2D() ) { this->UpdateShaderParameter(renderer); this->GenerateDataForRenderer( renderer ); } } void mitk::FiberBundleMapper2D::UpdateShaderParameter(mitk::BaseRenderer *) { // see new vtkShaderCallback } // vtkActors and Mappers are feeded here void mitk::FiberBundleMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { mitk::FiberBundle* fiberBundle = this->GetInput(); //the handler of local storage gets feeded in this method with requested data for related renderwindow FBXLocalStorage *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); mitk::DataNode* node = this->GetDataNode(); if (node == nullptr) return; vtkSmartPointer fiberPolyData = fiberBundle->GetFiberPolyData(); if (fiberPolyData == nullptr) return; fiberPolyData->GetPointData()->AddArray(fiberBundle->GetFiberColors()); localStorage->m_FiberMapper->ScalarVisibilityOn(); localStorage->m_FiberMapper->SetScalarModeToUsePointFieldData(); localStorage->m_FiberMapper->SetLookupTable(m_lut); //apply the properties after the slice was set - localStorage->m_PointActor->GetProperty()->SetOpacity(0.999); localStorage->m_FiberMapper->SelectColorArray("FIBER_COLORS"); localStorage->m_FiberMapper->SetInputData(fiberPolyData); localStorage->m_FiberMapper->SetVertexShaderCode( "//VTK::System::Dec\n" "attribute vec4 vertexMC;\n" "//VTK::Normal::Dec\n" "uniform mat4 MCDCMatrix;\n" "//VTK::Color::Dec\n" "varying vec4 positionWorld;\n" "varying vec4 colorVertex;\n" "void main(void)\n" "{\n" " colorVertex = scalarColor;\n" " positionWorld = vertexMC;\n" " gl_Position = MCDCMatrix * vertexMC;\n" "}\n" ); + localStorage->m_FiberMapper->SetFragmentShaderCode( "//VTK::System::Dec\n" // always start with this line "//VTK::Output::Dec\n" // always have this line in your FS "uniform vec4 slicingPlane;\n" "uniform float fiberThickness;\n" "uniform int fiberFadingON;\n" "uniform float fiberOpacity;\n" "varying vec4 positionWorld;\n" "varying vec4 colorVertex;\n" "out vec4 out_Color;\n" "void main(void)\n" "{\n" " float r1 = dot(positionWorld.xyz, slicingPlane.xyz) - slicingPlane.w;\n" " if (abs(r1) >= fiberThickness)\n" " discard;\n" " if (fiberFadingON != 0)\n" " {\n" " float x = (r1 + fiberThickness) / (fiberThickness*2.0);\n" " x = 1.0 - x;\n" " out_Color = vec4(colorVertex.xyz*x, fiberOpacity);\n" " }\n" " else{\n" " out_Color = vec4(colorVertex.xyz,fiberOpacity);\n" " }\n" "}\n" ); vtkSmartPointer myCallback = vtkSmartPointer::New(); myCallback->renderer = renderer; myCallback->node = this->GetDataNode(); localStorage->m_FiberMapper->AddObserver(vtkCommand::UpdateShaderEvent,myCallback); localStorage->m_PointActor->SetMapper(localStorage->m_FiberMapper); - localStorage->m_PointActor->GetProperty()->ShadingOn(); localStorage->m_PointActor->GetProperty()->SetLineWidth(m_LineWidth); // We have been modified => save this for next Update() localStorage->m_LastUpdateTime.Modified(); } vtkProp* mitk::FiberBundleMapper2D::GetVtkProp(mitk::BaseRenderer *renderer) { this->Update(renderer); return m_LocalStorageHandler.GetLocalStorage(renderer)->m_PointActor; } void mitk::FiberBundleMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { Superclass::SetDefaultProperties(node, renderer, overwrite); // node->SetProperty("shader",mitk::ShaderProperty::New("mitkShaderFiberClipping")); //add other parameters to propertylist node->AddProperty( "Fiber2DSliceThickness", mitk::FloatProperty::New(1.0f), renderer, overwrite ); node->AddProperty( "Fiber2DfadeEFX", mitk::BoolProperty::New(true), renderer, overwrite ); node->AddProperty( "color", mitk::ColorProperty::New(1.0,1.0,1.0), renderer, overwrite); } mitk::FiberBundleMapper2D::FBXLocalStorage::FBXLocalStorage() { m_PointActor = vtkSmartPointer::New(); m_FiberMapper = vtkSmartPointer::New(); } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.h b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.h index 4542c21d0e..89ec23dfa2 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.h +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.h @@ -1,110 +1,86 @@ /*=================================================================== 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 FiberBundleMAPPER2D_H_HEADER_INCLUDED #define FiberBundleMAPPER2D_H_HEADER_INCLUDED -//MITK Rendering #include #include -//#include - #include #include #include #define MITKFIBERBUNDLEMAPPER2D_POLYDATAMAPPER vtkOpenGLPolyDataMapper class vtkActor; -//class vtkPropAssembly; //lets see if we need it class mitkBaseRenderer; class MITKFIBERBUNDLEMAPPER2D_POLYDATAMAPPER; class vtkCutter; class vtkPlane; class vtkPolyData; - - namespace mitk { struct IShaderRepository; class FiberBundleMapper2D : public VtkMapper { public: - mitkClassMacro(FiberBundleMapper2D, VtkMapper); - itkFactorylessNewMacro(Self) - itkCloneMacro(Self) - mitk::FiberBundle* GetInput(); - - - /** \brief Checks whether this mapper needs to update itself and generate data. */ - void Update(mitk::BaseRenderer * renderer) override; - - - static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = nullptr, bool overwrite = false ); - - - //### methods of MITK-VTK rendering pipeline - vtkProp* GetVtkProp(mitk::BaseRenderer* renderer) override; - //### end of methods of MITK-VTK rendering pipeline - - - class FBXLocalStorage : public mitk::Mapper::BaseLocalStorage + mitkClassMacro(FiberBundleMapper2D, VtkMapper); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + mitk::FiberBundle* GetInput(); + void Update(mitk::BaseRenderer * renderer) override; + static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = nullptr, bool overwrite = false ); + vtkProp* GetVtkProp(mitk::BaseRenderer* renderer) override; + + class FBXLocalStorage : public mitk::Mapper::BaseLocalStorage + { + public: + vtkSmartPointer m_PointActor; + vtkSmartPointer m_FiberMapper; + itk::TimeStamp m_LastUpdateTime; + FBXLocalStorage(); + + ~FBXLocalStorage() override { - public: - /** \brief Point Actor of a 2D render window. */ - vtkSmartPointer m_PointActor; - /** \brief Point Mapper of a 2D render window. */ - vtkSmartPointer m_FiberMapper; - vtkSmartPointer m_SlicingPlane; //needed later when optimized 2D mapper - vtkSmartPointer m_SlicedResult; //might be depricated in optimized 2D mapper - - /** \brief Timestamp of last update of stored data. */ - itk::TimeStamp m_LastUpdateTime; - /** \brief Constructor of the local storage. Do as much actions as possible in here to avoid double executions. */ - FBXLocalStorage(); //if u copy&paste from this 2Dmapper, be aware that the implementation of this constructor is in the cpp file - - ~FBXLocalStorage() override - { - } - }; - - /** \brief This member holds all three LocalStorages for the three 2D render windows. */ - mitk::LocalStorageHandler m_LocalStorageHandler; - + } + }; + /** \brief This member holds all three LocalStorages for the three 2D render windows. */ + mitk::LocalStorageHandler m_LocalStorageHandler; protected: - FiberBundleMapper2D(); - ~FiberBundleMapper2D() override; + FiberBundleMapper2D(); + ~FiberBundleMapper2D() override; - /** Does the actual resampling, without rendering. */ - void GenerateDataForRenderer(mitk::BaseRenderer*) override; + /** Does the actual resampling, without rendering. */ + void GenerateDataForRenderer(mitk::BaseRenderer*) override; - void UpdateShaderParameter(mitk::BaseRenderer*); + void UpdateShaderParameter(mitk::BaseRenderer*); private: - vtkSmartPointer m_lut; + vtkSmartPointer m_lut; - int m_LineWidth; + int m_LineWidth; }; }//end namespace #endif diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.cpp index 1b5a8310a8..2961bfe0f4 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.cpp @@ -1,421 +1,253 @@ /*=================================================================== 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 "mitkFiberBundleMapper3D.h" #include #include #include #include #include #include #include #include #include #include #include #include #include - -class vtkShaderCallback3D : public vtkCommand -{ -public: - static vtkShaderCallback3D *New() - { - return new vtkShaderCallback3D; - } - mitk::BaseRenderer *renderer; - mitk::DataNode *node; - - void Execute(vtkObject *, unsigned long, void* cbo) override - { - vtkShaderProgram *program = reinterpret_cast(cbo); - - float fiberOpacity; - node->GetOpacity(fiberOpacity, nullptr); - program->SetUniformf("fiberOpacity", fiberOpacity); - - if (this->renderer) - { - mitk::Vector3D plane_vec; plane_vec.Fill(0); - node->GetPropertyValue("Fiber3DClippingPlane",plane_vec); - float distance = plane_vec.GetNorm(); - plane_vec.Normalize(); - - bool flip; - node->GetBoolProperty("Fiber3DClippingPlaneFlip",flip); - - if (flip) - { - plane_vec *= -1; - distance *= -1; - } - - node->GetBoolProperty("Fiber3DClippingPlaneSecondFlip",flip); - if (flip) - { - plane_vec *= -1; - distance *= -1; - } - - float a[4]; - for (int i = 0; i < 3; ++i) - a[i] = plane_vec[i]; - - a[3] = distance; - program->SetUniform4f("slicingPlane", a); - - float v = 1; - node->GetFloatProperty("light.ambient", v); - program->SetUniformf("ambient", v); - - node->GetFloatProperty("light.diffuse", v); - program->SetUniformf("diffuse", v); - - node->GetFloatProperty("light.specular", v); - program->SetUniformf("intensity", v); - - node->GetFloatProperty("light.intensity", v); - program->SetUniformf("intensity", v); - - bool enable_light = false; - node->GetBoolProperty("light.enable_light", enable_light); - program->SetUniformi("enable_light", enable_light); - } - } - - vtkShaderCallback3D() { this->renderer = nullptr; } -}; +#include +#include mitk::FiberBundleMapper3D::FiberBundleMapper3D() : m_TubeRadius(0.0) , m_TubeSides(15) , m_LineWidth(1) { - m_lut = vtkLookupTable::New(); + m_lut = vtkSmartPointer::New(); m_lut->Build(); } mitk::FiberBundleMapper3D::~FiberBundleMapper3D() { } const mitk::FiberBundle* mitk::FiberBundleMapper3D::GetInput() { return static_cast ( GetDataNode()->GetData() ); } /* This method is called once the mapper gets new input, for UI rotation or changes in colorcoding this method is NOT called */ void mitk::FiberBundleMapper3D::InternalGenerateData(mitk::BaseRenderer *renderer) { m_FiberPolyData->GetPointData()->AddArray(m_FiberBundle->GetFiberColors()); - float tmpopa; - this->GetDataNode()->GetOpacity(tmpopa, nullptr); - FBXLocalStorage3D *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); + LocalStorage3D *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); if (m_TubeRadius>0.0) { vtkSmartPointer tubeFilter = vtkSmartPointer::New(); tubeFilter->SetInputData(m_FiberPolyData); tubeFilter->SetNumberOfSides(m_TubeSides); tubeFilter->SetRadius(m_TubeRadius); tubeFilter->Update(); m_FiberPolyData = tubeFilter->GetOutput(); } else if (m_RibbonWidth>0.0) { vtkSmartPointer tubeFilter = vtkSmartPointer::New(); tubeFilter->SetInputData(m_FiberPolyData); tubeFilter->SetWidth(m_RibbonWidth); tubeFilter->Update(); m_FiberPolyData = tubeFilter->GetOutput(); } - if (tmpopa<1) - { - vtkSmartPointer depthSort = vtkSmartPointer::New(); - depthSort->SetInputData( m_FiberPolyData ); - depthSort->SetCamera( renderer->GetVtkRenderer()->GetActiveCamera() ); - depthSort->SetDirectionToBackToFront(); - depthSort->Update(); - localStorage->m_FiberMapper->SetInputConnection(depthSort->GetOutputPort()); - - } - else - { +// if (tmpopa<1) +// { +// vtkSmartPointer depthSort = vtkSmartPointer::New(); +// depthSort->SetInputData( m_FiberPolyData ); +// depthSort->SetCamera( renderer->GetVtkRenderer()->GetActiveCamera() ); +// depthSort->SetDirectionToBackToFront(); +// depthSort->Update(); +// localStorage->m_FiberMapper->SetInputConnection(depthSort->GetOutputPort()); + +// } +// else +// { localStorage->m_FiberMapper->SetInputData(m_FiberPolyData); - } - - if (m_Lighting) - { - float floatProp = 1.0; - GetDataNode()->GetFloatProperty("light.ambient", floatProp); - localStorage->m_FiberActor->GetProperty()->SetAmbient(floatProp); - GetDataNode()->GetFloatProperty("light.diffuse", floatProp); - localStorage->m_FiberActor->GetProperty()->SetDiffuse(floatProp); - GetDataNode()->GetFloatProperty("light.specular", floatProp); - localStorage->m_FiberActor->GetProperty()->SetSpecular(floatProp); - GetDataNode()->GetFloatProperty("light.specularpower", floatProp); - localStorage->m_FiberActor->GetProperty()->SetSpecularPower( floatProp ); - - mitk::ColorProperty* ambientC = dynamic_cast(GetDataNode()->GetProperty("light.ambientcolor")); - mitk::ColorProperty* diffuseC = dynamic_cast(GetDataNode()->GetProperty("light.diffusecolor")); - mitk::ColorProperty* specularC = dynamic_cast(GetDataNode()->GetProperty("light.specularcolor")); - - localStorage->m_FiberActor->GetProperty()->SetAmbientColor( ambientC->GetColor()[0], ambientC->GetColor()[1], ambientC->GetColor()[2] ); - localStorage->m_FiberActor->GetProperty()->SetDiffuseColor( diffuseC->GetColor()[0], diffuseC->GetColor()[1], diffuseC->GetColor()[2] ); - localStorage->m_FiberActor->GetProperty()->SetSpecularColor( specularC->GetColor()[0], specularC->GetColor()[1], specularC->GetColor()[2] ); - localStorage->m_FiberActor->GetProperty()->SetLighting(true); - } - else - { - localStorage->m_FiberActor->GetProperty()->SetLighting(false); - } +// } localStorage->m_FiberMapper->SelectColorArray("FIBER_COLORS"); localStorage->m_FiberMapper->ScalarVisibilityOn(); localStorage->m_FiberMapper->SetScalarModeToUsePointFieldData(); localStorage->m_FiberActor->SetMapper(localStorage->m_FiberMapper); localStorage->m_FiberMapper->SetLookupTable(m_lut); - - // set Opacity - localStorage->m_FiberActor->GetProperty()->SetOpacity((double) tmpopa); localStorage->m_FiberActor->GetProperty()->SetLineWidth(m_LineWidth); - localStorage->m_FiberAssembly->AddPart(localStorage->m_FiberActor); -// localStorage->m_FiberMapper->AddShaderReplacement( -// vtkShader::Vertex, -// "//VTK::Normal::Dec\n", -// true, -// "//VTK::Normal::Dec\n" -// "uniform mat4 MCVCMatrix;\n" -// "attribute vec3 normalMC;\n" -// "uniform mat3 normalMatrix;\n" -// "varying vec4 positionWorld;\n" -// "varying vec4 colorVertex;\n" -// "varying vec3 N;\n" -// "varying vec4 v;\n", -// false -// ); - - localStorage->m_FiberMapper->SetVertexShaderCode( - "//VTK::System::Dec\n" - "attribute vec4 vertexMC;\n" - - "//VTK::Normal::Dec\n" - "uniform mat4 MCDCMatrix;\n" - "uniform mat4 MCVCMatrix;\n" - - "//VTK::Color::Dec\n" - "attribute vec3 normalMC;\n" - "uniform mat3 normalMatrix;\n" - - "varying vec4 positionWorld;\n" - "varying vec4 colorVertex;\n" - "varying vec3 N;\n" - "varying vec4 v;\n" - - "void main(void)\n" - "{\n" - " colorVertex = scalarColor;\n" - " positionWorld = vertexMC;\n" - " v = MCVCMatrix * vertexMC;\n" - " mat4 glNormalMatrix = transpose(inverse(MCVCMatrix));\n" - " N = normalize(normalMatrix * normalMC);\n" - " gl_Position = MCDCMatrix * vertexMC;\n" - "}\n" - ); - localStorage->m_FiberMapper->SetFragmentShaderCode( - "//VTK::System::Dec\n" // always start with this line - "//VTK::Output::Dec\n" // always have this line in your FS - - "uniform vec4 slicingPlane;\n" - "uniform float fiberOpacity;\n" - "uniform float ambient;\n" - "uniform float diffuse;\n" - "uniform float specular;\n" - "uniform float intensity;\n" - "uniform int enable_light;\n" - "varying vec4 positionWorld;\n" - "varying vec4 colorVertex;\n" - - "varying vec3 N;\n" - "varying vec4 v;\n" - "out vec4 out_Color;\n" - - "void main(void)\n" - "{\n" - " float r1 = dot(positionWorld.xyz, slicingPlane.xyz) - slicingPlane.w;\n" - " if ( r1 > 0 )\n" - " discard;\n" - - " if (enable_light!=0)\n" - " {\n" - " vec3 L = normalize(-v.xyz);\n" -// "normalize(gl_LightSource[0].position.xyz - v.xyz);\n" - " vec3 E = normalize(-v.xyz); // we are in Eye Coordinates, so EyePos is (0,0,0)\n" - " vec3 R = normalize(-reflect(L,N));\n" - - //calculate Diffuse Term: - " float Idiff = diffuse * max(dot(N,L), 0.0);\n" - " Idiff = clamp(Idiff, 0.0, 1.0);\n" - - // calculate Specular Term: - " float Ispec = specular * pow(max(dot(R,E),0.0),0.3);\n" - " Ispec = clamp(Ispec, 0.0, 1.0);\n" - - " out_Color = vec4(colorVertex.xyz, fiberOpacity)*(1-intensity) + vec4(colorVertex.xyz * (ambient + Idiff + Ispec) * intensity, fiberOpacity);\n" - " }\n" - " else\n" - " {\n" - " out_Color = vec4(colorVertex.xyz, fiberOpacity);\n" - " }\n" - - "}\n" - ); - - - vtkSmartPointer myCallback = vtkSmartPointer::New(); - myCallback->renderer = renderer; - myCallback->node = this->GetDataNode(); - localStorage->m_FiberMapper->AddObserver(vtkCommand::UpdateShaderEvent,myCallback); - + const DataNode* node = this->GetDataNode(); + mitk::ClippingProperty* prop = dynamic_cast(node->GetProperty("3DClipping")); + + mitk::Vector3D plane_normal = prop->GetNormal(); + mitk::Point3D plane_origin = prop->GetOrigin(); + bool flip; + node->GetBoolProperty("3DClippingPlaneFlip",flip); + if (flip) + plane_normal *= -1; + + vtkSmartPointer plane = vtkSmartPointer::New(); + double vp[3], vnormal[3]; + vp[0] = plane_origin[0]; vp[1] = plane_origin[1]; vp[2] = plane_origin[2]; + vnormal[0] = plane_normal[0]; vnormal[1] = plane_normal[1]; vnormal[2] = plane_normal[2]; + plane->SetOrigin(vp); + plane->SetNormal(vnormal); + + localStorage->m_FiberMapper->RemoveAllClippingPlanes(); + if (plane_normal.GetNorm() > 0.0) + localStorage->m_FiberMapper->AddClippingPlane(plane); localStorage->m_LastUpdateTime.Modified(); } void mitk::FiberBundleMapper3D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; const DataNode* node = this->GetDataNode(); - FBXLocalStorage3D* localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); + LocalStorage3D* localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); m_FiberBundle = dynamic_cast(node->GetData()); m_FiberPolyData = m_FiberBundle->GetFiberPolyData(); - // this->ApplyShaderProperties(renderer, "shader_3d"); - // did any rendering properties change? float tubeRadius = 0; node->GetFloatProperty("shape.tuberadius", tubeRadius); if (m_TubeRadius!=tubeRadius) { m_TubeRadius = tubeRadius; m_FiberBundle->RequestUpdate3D(); } int tubeSides = 0; node->GetIntProperty("shape.tubesides", tubeSides); if (m_TubeSides!=tubeSides) { m_TubeSides = tubeSides; m_FiberBundle->RequestUpdate3D(); } int lineWidth = 0; node->GetIntProperty("shape.linewidth", lineWidth); if (m_LineWidth!=lineWidth) { m_LineWidth = lineWidth; m_FiberBundle->RequestUpdate3D(); } float ribbonWidth = 0; node->GetFloatProperty("shape.ribbonwidth", ribbonWidth); if (m_RibbonWidth!=ribbonWidth) { m_RibbonWidth = ribbonWidth; m_FiberBundle->RequestUpdate3D(); } - bool lighting = false; - node->GetBoolProperty("light.enable", lighting); - if (m_Lighting!=lighting) - { - m_Lighting = lighting; - m_FiberBundle->RequestUpdate3D(); - } + float opacity; + this->GetDataNode()->GetOpacity(opacity, nullptr); + vtkProperty *property = localStorage->m_FiberActor->GetProperty(); + + float v = 1; + node->GetFloatProperty("light.ambient", v); + property->SetAmbient(v); + + node->GetFloatProperty("light.diffuse", v); + property->SetDiffuse(v); + + node->GetFloatProperty("light.specular", v); + property->SetSpecular(v); + + node->GetFloatProperty("light.specularpower", v); + property->SetSpecularPower(v); + + property->SetLighting(true); + property->SetOpacity(opacity); if (localStorage->m_LastUpdateTime>=m_FiberBundle->GetUpdateTime3D()) return; // Calculate time step of the input data for the specified renderer (integer value) // this method is implemented in mitkMapper this->CalculateTimeStep( renderer ); this->InternalGenerateData(renderer); } void mitk::FiberBundleMapper3D::UpdateShaderParameter(mitk::BaseRenderer * ) { // see new vtkShaderCallback3D } void mitk::FiberBundleMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { Superclass::SetDefaultProperties(node, renderer, overwrite); mitk::Vector3D plane_vec; plane_vec.Fill(0.0); - node->AddProperty( "Fiber3DClippingPlane", mitk::Vector3DProperty::New( plane_vec ), renderer, overwrite ); - node->AddProperty( "Fiber3DClippingPlaneId", mitk::IntProperty::New( 0 ), renderer, overwrite ); - node->AddProperty( "Fiber3DClippingPlaneFlip", mitk::BoolProperty::New( false ), renderer, overwrite ); - node->AddProperty( "Fiber3DClippingPlaneSecondFlip", mitk::BoolProperty::New( false ), renderer, overwrite ); + mitk::Point3D plane_origin; plane_origin.Fill(0.0); + node->AddProperty( "3DClipping", mitk::ClippingProperty::New( plane_origin, plane_vec ), renderer, overwrite ); + node->AddProperty( "3DClippingPlaneId", mitk::IntProperty::New(-1), renderer, overwrite ); + node->AddProperty( "3DClippingPlaneFlip", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "opacity", mitk::FloatProperty::New( 1.0 ), renderer, overwrite); node->AddProperty( "color", mitk::ColorProperty::New(1.0,1.0,1.0), renderer, overwrite); node->AddProperty( "pickable", mitk::BoolProperty::New( true ), renderer, overwrite); - node->AddProperty( "shape.linewidth", mitk::IntProperty::New( true ), renderer, overwrite ); + node->AddProperty( "shape.linewidth", mitk::IntProperty::New( 1 ), renderer, overwrite ); node->AddProperty( "shape.tuberadius",mitk::FloatProperty::New( 0.0 ), renderer, overwrite); node->AddProperty( "shape.tubesides",mitk::IntProperty::New( 15 ), renderer, overwrite); node->AddProperty( "shape.ribbonwidth", mitk::FloatProperty::New( 0.0 ), renderer, overwrite); - node->AddProperty( "light.intensity", mitk::FloatProperty::New( 0.6 ), renderer, overwrite); - node->AddProperty( "light.enable_light", mitk::BoolProperty::New( false ), renderer, overwrite); node->AddProperty( "light.ambient", mitk::FloatProperty::New( 0.05 ), renderer, overwrite); - node->AddProperty( "light.diffuse", mitk::FloatProperty::New( 1.0 ), renderer, overwrite); - node->AddProperty( "light.specular", mitk::FloatProperty::New( 0.0 ), renderer, overwrite); - node->AddProperty( "light.specularpower", mitk::FloatProperty::New( 1.0 ), renderer, overwrite); + node->AddProperty( "light.diffuse", mitk::FloatProperty::New( 0.9 ), renderer, overwrite); + node->AddProperty( "light.specular", mitk::FloatProperty::New( 1.0 ), renderer, overwrite); + + node->AddProperty( "light.specularpower", mitk::FloatProperty::New( 16.0 ), renderer, overwrite); node->AddProperty( "light.ambientcolor", mitk::ColorProperty::New(1,1,1), renderer, overwrite); node->AddProperty( "light.diffusecolor", mitk::ColorProperty::New(1,1,1), renderer, overwrite); node->AddProperty( "light.specularcolor", mitk::ColorProperty::New(1,1,1), renderer, overwrite); } vtkProp* mitk::FiberBundleMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { return m_LocalStorageHandler.GetLocalStorage(renderer)->m_FiberAssembly; } -mitk::FiberBundleMapper3D::FBXLocalStorage3D::FBXLocalStorage3D() +mitk::FiberBundleMapper3D::LocalStorage3D::LocalStorage3D() { m_FiberActor = vtkSmartPointer::New(); m_FiberMapper = vtkSmartPointer::New(); m_FiberAssembly = vtkSmartPointer::New(); } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.h b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.h index 7c1e584a0b..4c9fdd97a1 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.h +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.h @@ -1,105 +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. ===================================================================*/ #ifndef FiberBundleMapper3D_H_HEADER_INCLUDED #define FiberBundleMapper3D_H_HEADER_INCLUDED #include #include - #include #include - -//#define MITKFIBERBUNDLEMAPPER3D_POLYDATAMAPPER vtkOpenGLPolyDataMapper - -//class MITKFIBERBUNDLEMAPPER3D_POLYDATAMAPPER; class vtkPropAssembly; class vtkPolyDataMapper; class vtkLookupTable; class vtkOpenGLActor; namespace mitk { //##Documentation //## @brief Mapper for FiberBundle //## @ingroup Mapper class FiberBundleMapper3D : public VtkMapper { public: - mitkClassMacro(FiberBundleMapper3D, VtkMapper) - itkFactorylessNewMacro(Self) - itkCloneMacro(Self) + mitkClassMacro(FiberBundleMapper3D, VtkMapper) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) - //========== essential implementation for 3D mapper ======== - const FiberBundle* GetInput(); - vtkProp *GetVtkProp(mitk::BaseRenderer *renderer) override; //looks like depricated.. should be replaced bz GetViewProp() - static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = nullptr, bool overwrite = false ); - void GenerateDataForRenderer(mitk::BaseRenderer* renderer) override; - //========================================================= + const FiberBundle* GetInput(); + vtkProp *GetVtkProp(mitk::BaseRenderer *renderer) override; //looks like depricated.. should be replaced bz GetViewProp() + static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = nullptr, bool overwrite = false ); + void GenerateDataForRenderer(mitk::BaseRenderer* renderer) override; - class FBXLocalStorage3D : public mitk::Mapper::BaseLocalStorage - { - public: - /** \brief Point Actor of a 3D render window. */ - vtkSmartPointer m_FiberActor; - /** \brief Point Mapper of a 3D render window. */ - vtkSmartPointer m_FiberMapper; - - vtkSmartPointer m_FiberAssembly; + class LocalStorage3D : public mitk::Mapper::BaseLocalStorage + { + public: + vtkSmartPointer m_FiberActor; + vtkSmartPointer m_FiberMapper; + vtkSmartPointer m_FiberAssembly; - /** \brief Timestamp of last update of stored data. */ - itk::TimeStamp m_LastUpdateTime; - /** \brief Constructor of the local storage. Do as much actions as possible in here to avoid double executions. */ - FBXLocalStorage3D(); //if u copy&paste from this 2Dmapper, be aware that the implementation of this constructor is in the cpp file + itk::TimeStamp m_LastUpdateTime; + LocalStorage3D(); - ~FBXLocalStorage3D() override - { - } - }; + ~LocalStorage3D() override + { + } + }; - /** \brief This member holds all three LocalStorages for the 3D render window(s). */ - mitk::LocalStorageHandler m_LocalStorageHandler; + /** \brief This member holds all three LocalStorages for the 3D render window(s). */ + mitk::LocalStorageHandler m_LocalStorageHandler; protected: - FiberBundleMapper3D(); - ~FiberBundleMapper3D() override; - void InternalGenerateData(mitk::BaseRenderer *renderer); + FiberBundleMapper3D(); + ~FiberBundleMapper3D() override; + void InternalGenerateData(mitk::BaseRenderer *renderer); - void UpdateShaderParameter(mitk::BaseRenderer*); + void UpdateShaderParameter(mitk::BaseRenderer*); private: - vtkSmartPointer m_lut; - float m_TubeRadius; - int m_TubeSides; - int m_LineWidth; - float m_RibbonWidth; - bool m_Lighting; - vtkSmartPointer m_FiberPolyData; - mitk::FiberBundle* m_FiberBundle; + vtkSmartPointer m_lut; + float m_TubeRadius; + int m_TubeSides; + int m_LineWidth; + float m_RibbonWidth; + bool m_Lighting; + vtkSmartPointer m_FiberPolyData; + mitk::FiberBundle* m_FiberBundle; }; } // end namespace mitk #endif /* FiberBundleMapper3D_H_HEADER_INCLUDED */ diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.cpp index 093d65304a..ef3ba90517 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.cpp @@ -1,123 +1,129 @@ /*=================================================================== 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 "mitkFiberTrackingObjectFactory.h" mitk::FiberTrackingObjectFactory::FiberTrackingObjectFactory() : CoreObjectFactoryBase() { } mitk::FiberTrackingObjectFactory::~FiberTrackingObjectFactory() { } mitk::Mapper::Pointer mitk::FiberTrackingObjectFactory::CreateMapper(mitk::DataNode* node, MapperSlotId id) { mitk::Mapper::Pointer newMapper=nullptr; if ( id == mitk::BaseRenderer::Standard2D ) { std::string classname("FiberBundle"); if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0) { newMapper = mitk::FiberBundleMapper2D::New(); newMapper->SetDataNode(node); } else if(node->GetData() && std::string("PeakImage").compare(node->GetData()->GetNameOfClass())==0) { newMapper = mitk::PeakImageMapper2D::New(); newMapper->SetDataNode(node); } } else if ( id == mitk::BaseRenderer::Standard3D ) { std::string classname("FiberBundle"); if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0) { newMapper = mitk::FiberBundleMapper3D::New(); newMapper->SetDataNode(node); } + else if(node->GetData() && std::string("PeakImage").compare(node->GetData()->GetNameOfClass())==0) + { + newMapper = mitk::PeakImageMapper3D::New(); + newMapper->SetDataNode(node); + } } return newMapper; } void mitk::FiberTrackingObjectFactory::SetDefaultProperties(mitk::DataNode* node) { std::string classname("FiberBundle"); if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0) { mitk::FiberBundleMapper3D::SetDefaultProperties(node); mitk::FiberBundleMapper2D::SetDefaultProperties(node); } else if (node->GetData() && std::string("PeakImage").compare(node->GetData()->GetNameOfClass())==0) { + mitk::PeakImageMapper3D::SetDefaultProperties(node); mitk::PeakImageMapper2D::SetDefaultProperties(node); } } const char* mitk::FiberTrackingObjectFactory::GetFileExtensions() { std::string fileExtension; this->CreateFileExtensions(m_FileExtensionsMap, fileExtension); return fileExtension.c_str(); } mitk::CoreObjectFactoryBase::MultimapType mitk::FiberTrackingObjectFactory::GetFileExtensionsMap() { return m_FileExtensionsMap; } const char* mitk::FiberTrackingObjectFactory::GetSaveFileExtensions() { std::string fileExtension; this->CreateFileExtensions(m_SaveFileExtensionsMap, fileExtension); return fileExtension.c_str(); } mitk::CoreObjectFactoryBase::MultimapType mitk::FiberTrackingObjectFactory::GetSaveFileExtensionsMap() { return m_SaveFileExtensionsMap; } void mitk::FiberTrackingObjectFactory::CreateFileExtensionsMap() { } void mitk::FiberTrackingObjectFactory::RegisterIOFactories() { } struct RegisterFiberTrackingObjectFactory{ RegisterFiberTrackingObjectFactory() : m_Factory( mitk::FiberTrackingObjectFactory::New() ) { mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory( m_Factory ); } ~RegisterFiberTrackingObjectFactory() { mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory( m_Factory ); } mitk::FiberTrackingObjectFactory::Pointer m_Factory; }; static RegisterFiberTrackingObjectFactory registerFiberTrackingObjectFactory; diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.h b/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.h index 0c5381a2fe..d761bf9a82 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.h +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.h @@ -1,71 +1,68 @@ /*=================================================================== 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 MITKFIBERTRACKINGOBJECTFACTORY_H #define MITKFIBERTRACKINGOBJECTFACTORY_H #include "mitkCoreObjectFactory.h" -//modernized fiberbundle datastrucutre -#include "mitkFiberBundle.h" -#include "mitkFiberBundleMapper3D.h" -#include "mitkFiberBundleMapper2D.h" +#include +#include +#include #include - -//#include "mitkFiberBundleThreadMonitorMapper3D.h" -//#include "mitkFiberBundleThreadMonitor.h" +#include namespace mitk { class FiberTrackingObjectFactory : public CoreObjectFactoryBase { public: mitkClassMacro(FiberTrackingObjectFactory,CoreObjectFactoryBase) itkFactorylessNewMacro(Self) itkCloneMacro(Self) ~FiberTrackingObjectFactory() override; Mapper::Pointer CreateMapper(mitk::DataNode* node, MapperSlotId slotId) override; void SetDefaultProperties(mitk::DataNode* node) override; const char* GetFileExtensions() override; mitk::CoreObjectFactoryBase::MultimapType GetFileExtensionsMap() override; const char* GetSaveFileExtensions() override; mitk::CoreObjectFactoryBase::MultimapType GetSaveFileExtensionsMap() override; void RegisterIOFactories(); protected: FiberTrackingObjectFactory(); private: void CreateFileExtensionsMap(); std::string m_ExternalFileExtensions; std::string m_InternalFileExtensions; std::string m_SaveFileExtensions; MultimapType m_FileExtensionsMap; MultimapType m_SaveFileExtensionsMap; }; } #endif // MITKFIBERTRACKINGOBJECTFACTORY_H diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.cpp index e9d5e1a7ad..12ffdb6e37 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.cpp @@ -1,240 +1,179 @@ /*=================================================================== 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 "mitkPeakImageMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkDataNode.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -class vtkPeakShaderCallback : public vtkCommand -{ -public: - static vtkPeakShaderCallback *New() - { - return new vtkPeakShaderCallback; - } - mitk::BaseRenderer *renderer; - mitk::DataNode *node; - - void Execute(vtkObject *, unsigned long, void*cbo) override - { - vtkShaderProgram *program = reinterpret_cast(cbo); - - - mitk::Image* image = dynamic_cast(node->GetData()); - mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); - - float minSpacing = 1; - if(spacing[0]GetOpacity(peakOpacity, nullptr); - - program->SetUniformf("peakOpacity", peakOpacity); - program->SetUniformf("clippingPlaneThickness", minSpacing/2); - - if (this->renderer) - { - //get information about current position of views - mitk::SliceNavigationController::Pointer sliceContr = renderer->GetSliceNavigationController(); - mitk::PlaneGeometry::ConstPointer planeGeo = sliceContr->GetCurrentPlaneGeometry(); - - //generate according cutting planes based on the view position - float planeNormal[3]; - planeNormal[0] = planeGeo->GetNormal()[0]; - planeNormal[1] = planeGeo->GetNormal()[1]; - planeNormal[2] = planeGeo->GetNormal()[2]; - - float tmp1 = planeGeo->GetOrigin()[0] * planeNormal[0]; - float tmp2 = planeGeo->GetOrigin()[1] * planeNormal[1]; - float tmp3 = planeGeo->GetOrigin()[2] * planeNormal[2]; - float thickness = tmp1 + tmp2 + tmp3; //attention, correct normalvector - - float* a = new float[4]; - for (int i = 0; i < 3; ++i) - a[i] = planeNormal[i]; - - a[3] = thickness; - program->SetUniform4f("slicingPlane", a); - } - } - - vtkPeakShaderCallback() { this->renderer = nullptr; } -}; - - mitk::PeakImageMapper2D::PeakImageMapper2D() { - m_lut = vtkLookupTable::New(); + m_lut = vtkSmartPointer::New(); m_lut->Build(); } mitk::PeakImageMapper2D::~PeakImageMapper2D() { } mitk::PeakImage* mitk::PeakImageMapper2D::GetInput() { return dynamic_cast< mitk::PeakImage * > ( GetDataNode()->GetData() ); } void mitk::PeakImageMapper2D::UpdateVtkTransform(mitk::BaseRenderer *) { // don't apply transform since the peak polydata is already in world coordinates. return; } void mitk::PeakImageMapper2D::Update(mitk::BaseRenderer * renderer) { mitk::DataNode* node = this->GetDataNode(); if (node == nullptr) return; bool visible = true; node->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; this->GenerateDataForRenderer( renderer ); } -void mitk::PeakImageMapper2D::UpdateShaderParameter(mitk::BaseRenderer *) -{ - // see new vtkPeakShaderCallback -} - // vtkActors and Mappers are feeded here void mitk::PeakImageMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { mitk::PeakImage* peakImage = this->GetInput(); //the handler of local storage gets feeded in this method with requested data for related renderwindow - FBXLocalStorage *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); + LocalStorage *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); vtkSmartPointer polyData = peakImage->GetPolyData(); if (polyData == nullptr) return; localStorage->m_Mapper->ScalarVisibilityOn(); localStorage->m_Mapper->SetScalarModeToUsePointFieldData(); localStorage->m_Mapper->SetLookupTable(m_lut); //apply the properties after the slice was set -// localStorage->m_PointActor->GetProperty()->SetOpacity(0.999); localStorage->m_Mapper->SelectColorArray("FIBER_COLORS"); - localStorage->m_Mapper->SetInputData(polyData); - localStorage->m_Mapper->SetVertexShaderCode( - "//VTK::System::Dec\n" - "attribute vec4 vertexMC;\n" - - "//VTK::Normal::Dec\n" - "uniform mat4 MCDCMatrix;\n" - - "//VTK::Color::Dec\n" - - "varying vec4 positionWorld;\n" - "varying vec4 colorVertex;\n" - - "void main(void)\n" - "{\n" - " colorVertex = scalarColor;\n" - " positionWorld = vertexMC;\n" - " gl_Position = MCDCMatrix * vertexMC;\n" - "}\n" - ); - localStorage->m_Mapper->SetFragmentShaderCode( - "//VTK::System::Dec\n" // always start with this line - "//VTK::Output::Dec\n" // always have this line in your FS - "uniform vec4 slicingPlane;\n" - "uniform float clippingPlaneThickness;\n" - "uniform float peakOpacity;\n" - "varying vec4 positionWorld;\n" - "varying vec4 colorVertex;\n" - "out vec4 out_Color;\n" - - "void main(void)\n" - "{\n" - " float r1 = dot(positionWorld.xyz, slicingPlane.xyz) - slicingPlane.w;\n" - - " if (abs(r1) >= clippingPlaneThickness)\n" - " discard;\n" - " out_Color = vec4(colorVertex.xyz,peakOpacity);\n" - "}\n" - ); - - vtkSmartPointer myCallback = vtkSmartPointer::New(); - myCallback->renderer = renderer; - myCallback->node = this->GetDataNode(); - localStorage->m_Mapper->AddObserver(vtkCommand::UpdateShaderEvent,myCallback); + + mitk::SliceNavigationController::Pointer sliceContr = renderer->GetSliceNavigationController(); + mitk::PlaneGeometry::ConstPointer planeGeo = sliceContr->GetCurrentPlaneGeometry(); + mitk::Point3D plane_origin = planeGeo->GetCenter(); + + mitk::DataNode* node = this->GetDataNode(); + mitk::Image* image = dynamic_cast(node->GetData()); + mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); + + localStorage->m_Mapper->RemoveAllClippingPlanes(); + float clipping_plane_thickness = 1; + if(spacing[0]GetNormal(); + double vnormal[3]; + double vp1[3]; + double vp2[3]; + + vp1[0] = plane_origin[0] + plane_normal[0] * clipping_plane_thickness; + vp1[1] = plane_origin[1] + plane_normal[1] * clipping_plane_thickness; + vp1[2] = plane_origin[2] + plane_normal[2] * clipping_plane_thickness; + + vp2[0] = plane_origin[0] - plane_normal[0] * clipping_plane_thickness; + vp2[1] = plane_origin[1] - plane_normal[1] * clipping_plane_thickness; + vp2[2] = plane_origin[2] - plane_normal[2] * clipping_plane_thickness; + + { + vnormal[0] = vp2[0] - vp1[0]; + vnormal[1] = vp2[1] - vp1[1]; + vnormal[2] = vp2[2] - vp1[2]; + + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetOrigin(vp1); + plane->SetNormal(vnormal); + localStorage->m_Mapper->AddClippingPlane(plane); + } + { + vnormal[0] = vp1[0] - vp2[0]; + vnormal[1] = vp1[1] - vp2[1]; + vnormal[2] = vp1[2] - vp2[2]; + + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetOrigin(vp2); + plane->SetNormal(vnormal); + localStorage->m_Mapper->AddClippingPlane(plane); + } localStorage->m_PointActor->SetMapper(localStorage->m_Mapper); - localStorage->m_PointActor->GetProperty()->ShadingOn(); float linewidth = 1.0; this->GetDataNode()->GetFloatProperty("shape.linewidth",linewidth); localStorage->m_PointActor->GetProperty()->SetLineWidth(linewidth); // We have been modified => save this for next Update() localStorage->m_LastUpdateTime.Modified(); } vtkProp* mitk::PeakImageMapper2D::GetVtkProp(mitk::BaseRenderer *renderer) { this->Update(renderer); return m_LocalStorageHandler.GetLocalStorage(renderer)->m_PointActor; } void mitk::PeakImageMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { - Superclass::SetDefaultProperties(node, renderer, overwrite); +// Superclass::SetDefaultProperties(node, renderer, overwrite); //add other parameters to propertylist node->AddProperty( "color", mitk::ColorProperty::New(1.0,1.0,1.0), renderer, overwrite); node->AddProperty( "shape.linewidth", mitk::FloatProperty::New(1.0), renderer, overwrite); } -mitk::PeakImageMapper2D::FBXLocalStorage::FBXLocalStorage() +mitk::PeakImageMapper2D::LocalStorage::LocalStorage() { m_PointActor = vtkSmartPointer::New(); m_Mapper = vtkSmartPointer::New(); } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.h b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.h index 066286c257..39e97b80e6 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.h +++ b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.h @@ -1,106 +1,85 @@ /*=================================================================== 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 PeakImageMapper2D_H_HEADER_INCLUDED #define PeakImageMapper2D_H_HEADER_INCLUDED //MITK Rendering #include #include #include #include #include #define MITKPeakImageMapper2D_POLYDATAMAPPER vtkOpenGLPolyDataMapper class vtkActor; class mitkBaseRenderer; class MITKPeakImageMapper2D_POLYDATAMAPPER; class vtkCutter; class vtkPlane; class vtkPolyData; namespace mitk { struct IShaderRepository; class PeakImageMapper2D : public VtkMapper { public: mitkClassMacro(PeakImageMapper2D, VtkMapper) itkFactorylessNewMacro(Self) itkCloneMacro(Self) - mitk::PeakImage* GetInput(); - - /** \brief Checks whether this mapper needs to update itself and generate data. */ + mitk::PeakImage* GetInput(); void Update(mitk::BaseRenderer * renderer) override; - - static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = nullptr, bool overwrite = false ); - void UpdateVtkTransform(mitk::BaseRenderer *renderer) override; - - //### methods of MITK-VTK rendering pipeline vtkProp* GetVtkProp(mitk::BaseRenderer* renderer) override; - //### end of methods of MITK-VTK rendering pipeline - - class FBXLocalStorage : public mitk::Mapper::BaseLocalStorage + class LocalStorage : public mitk::Mapper::BaseLocalStorage { public: - /** \brief Point Actor of a 2D render window. */ vtkSmartPointer m_PointActor; - /** \brief Point Mapper of a 2D render window. */ vtkSmartPointer m_Mapper; - vtkSmartPointer m_SlicingPlane; //needed later when optimized 2D mapper - vtkSmartPointer m_SlicedResult; //might be depricated in optimized 2D mapper - /** \brief Timestamp of last update of stored data. */ itk::TimeStamp m_LastUpdateTime; - /** \brief Constructor of the local storage. Do as much actions as possible in here to avoid double executions. */ - FBXLocalStorage(); //if u copy&paste from this 2Dmapper, be aware that the implementation of this constructor is in the cpp file + LocalStorage(); - ~FBXLocalStorage() override + ~LocalStorage() override { } }; /** \brief This member holds all three LocalStorages for the three 2D render windows. */ - mitk::LocalStorageHandler m_LocalStorageHandler; - - + mitk::LocalStorageHandler m_LocalStorageHandler; protected: PeakImageMapper2D(); ~PeakImageMapper2D() override; - - /** Does the actual resampling, without rendering. */ void GenerateDataForRenderer(mitk::BaseRenderer*) override; - void UpdateShaderParameter(mitk::BaseRenderer*); - private: vtkSmartPointer m_lut; }; }//end namespace #endif diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper3D.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper3D.cpp new file mode 100644 index 0000000000..77233f9842 --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper3D.cpp @@ -0,0 +1,194 @@ +/*=================================================================== + +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 "mitkPeakImageMapper3D.h" +#include "mitkBaseRenderer.h" +#include "mitkDataNode.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +mitk::PeakImageMapper3D::PeakImageMapper3D() +{ + m_lut = vtkSmartPointer::New(); + m_lut->Build(); +} + +mitk::PeakImageMapper3D::~PeakImageMapper3D() +{ +} + + +mitk::PeakImage* mitk::PeakImageMapper3D::GetInput() +{ + return dynamic_cast< mitk::PeakImage * > ( GetDataNode()->GetData() ); +} + +void mitk::PeakImageMapper3D::UpdateVtkTransform(mitk::BaseRenderer *) +{ + // don't apply transform since the peak polydata is already in world coordinates. + return; +} + +void mitk::PeakImageMapper3D::Update(mitk::BaseRenderer * renderer) +{ + mitk::DataNode* node = this->GetDataNode(); + if (node == nullptr) + return; + + bool visible = true; + node->GetVisibility(visible, renderer, "visible"); + if ( !visible ) + return; + + this->GenerateDataForRenderer( renderer ); +} + +// vtkActors and Mappers are feeded here +void mitk::PeakImageMapper3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) +{ + //the handler of local storage gets feeded in this method with requested data for related renderwindow + LocalStorage *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); + + bool enabled = false; + this->GetDataNode()->GetBoolProperty("Enable3DPeaks",enabled); + if (!enabled) + { + vtkSmartPointer polyData = vtkSmartPointer::New(); + localStorage->m_Mapper->SetInputData(polyData); + localStorage->m_Actor->SetMapper(localStorage->m_Mapper); + localStorage->m_Assembly->AddPart(localStorage->m_Actor); + return; + } + + mitk::PeakImage* peakImage = this->GetInput(); + vtkSmartPointer polyData = peakImage->GetPolyData(); + if (polyData == nullptr) + return; + + float linewidth = 1.0; + this->GetDataNode()->GetFloatProperty("shape.linewidth",linewidth); + + localStorage->m_Mapper->SetInputData(polyData); + localStorage->m_Mapper->SelectColorArray("FIBER_COLORS"); + localStorage->m_Mapper->ScalarVisibilityOn(); + localStorage->m_Mapper->SetScalarModeToUsePointFieldData(); + localStorage->m_Actor->SetMapper(localStorage->m_Mapper); + localStorage->m_Mapper->SetLookupTable(m_lut); + localStorage->m_Actor->GetProperty()->SetLineWidth(linewidth); + localStorage->m_Assembly->AddPart(localStorage->m_Actor); + + const DataNode* node = this->GetDataNode(); + mitk::ClippingProperty* prop = dynamic_cast(node->GetProperty("3DClipping")); + + mitk::Image* image = dynamic_cast(node->GetData()); + localStorage->m_Mapper->RemoveAllClippingPlanes(); + mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); + float clipping_plane_thickness = 1; + if(spacing[0]GetNormal(); + if (plane_normal.GetNorm()>0.0) + { + mitk::Point3D plane_origin = prop->GetOrigin(); + + double vnormal[3]; + double vp1[3]; + double vp2[3]; + + vp1[0] = plane_origin[0] + plane_normal[0] * clipping_plane_thickness; + vp1[1] = plane_origin[1] + plane_normal[1] * clipping_plane_thickness; + vp1[2] = plane_origin[2] + plane_normal[2] * clipping_plane_thickness; + + vp2[0] = plane_origin[0] - plane_normal[0] * clipping_plane_thickness; + vp2[1] = plane_origin[1] - plane_normal[1] * clipping_plane_thickness; + vp2[2] = plane_origin[2] - plane_normal[2] * clipping_plane_thickness; + + { + vnormal[0] = vp2[0] - vp1[0]; + vnormal[1] = vp2[1] - vp1[1]; + vnormal[2] = vp2[2] - vp1[2]; + + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetOrigin(vp1); + plane->SetNormal(vnormal); + localStorage->m_Mapper->AddClippingPlane(plane); + } + { + vnormal[0] = vp1[0] - vp2[0]; + vnormal[1] = vp1[1] - vp2[1]; + vnormal[2] = vp1[2] - vp2[2]; + + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetOrigin(vp2); + plane->SetNormal(vnormal); + localStorage->m_Mapper->AddClippingPlane(plane); + } + } + + // We have been modified => save this for next Update() + localStorage->m_LastUpdateTime.Modified(); +} + + +vtkProp* mitk::PeakImageMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) +{ + return m_LocalStorageHandler.GetLocalStorage(renderer)->m_Assembly; +} + + +void mitk::PeakImageMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) +{ +// Superclass::SetDefaultProperties(node, renderer, overwrite); + + mitk::Vector3D plane_vec; plane_vec.Fill(0.0); + mitk::Point3D plane_origin; plane_origin.Fill(0.0); + node->AddProperty( "3DClipping", mitk::ClippingProperty::New( plane_origin, plane_vec ), renderer, overwrite ); + node->AddProperty( "3DClippingPlaneId", mitk::IntProperty::New(-1), renderer, overwrite ); + node->AddProperty( "3DClippingPlaneFlip", mitk::BoolProperty::New( false ), renderer, overwrite ); + node->AddProperty( "Enable3DPeaks", mitk::BoolProperty::New( false ), renderer, overwrite ); +} + + +mitk::PeakImageMapper3D::LocalStorage::LocalStorage() +{ + m_Actor = vtkSmartPointer::New(); + m_Mapper = vtkSmartPointer::New(); + m_Assembly = vtkSmartPointer::New(); +} diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper3D.h b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper3D.h new file mode 100644 index 0000000000..09891bafff --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper3D.h @@ -0,0 +1,85 @@ +/*=================================================================== + +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 PeakImageMapper3D_H_HEADER_INCLUDED +#define PeakImageMapper3D_H_HEADER_INCLUDED + +//MITK Rendering +#include +#include +#include +#include +#include + +#define MITKPeakImageMapper3D_POLYDATAMAPPER vtkOpenGLPolyDataMapper + +class vtkActor; +class mitkBaseRenderer; +class MITKPeakImageMapper3D_POLYDATAMAPPER; +class vtkCutter; +class vtkPlane; +class vtkPolyData; + + + +namespace mitk { + +struct IShaderRepository; + +class PeakImageMapper3D : public VtkMapper +{ + +public: + mitkClassMacro(PeakImageMapper3D, VtkMapper) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + mitk::PeakImage* GetInput(); + void Update(mitk::BaseRenderer * renderer) override; + static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = nullptr, bool overwrite = false ); + void UpdateVtkTransform(mitk::BaseRenderer *renderer) override; + vtkProp* GetVtkProp(mitk::BaseRenderer* renderer) override; + + class LocalStorage : public mitk::Mapper::BaseLocalStorage + { + public: + vtkSmartPointer m_Actor; + vtkSmartPointer m_Mapper; + vtkSmartPointer m_Assembly; + + itk::TimeStamp m_LastUpdateTime; + LocalStorage(); + + ~LocalStorage() override + { + } + }; + + mitk::LocalStorageHandler m_LocalStorageHandler; + +protected: + PeakImageMapper3D(); + ~PeakImageMapper3D() override; + void GenerateDataForRenderer(mitk::BaseRenderer*) override; + +private: + vtkSmartPointer m_lut; +}; + + +}//end namespace + +#endif diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberMapper3DTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberMapper3DTest.cpp index 7371e3c386..2bb40f8e84 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberMapper3DTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberMapper3DTest.cpp @@ -1,115 +1,162 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include -#include - - -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ +#include #include "mitkTestingMacros.h" #include #include #include #include -#include #include -#include #include class mitkFiberMapper3DTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkFiberMapper3DTestSuite); - MITK_TEST(Test1); + MITK_TEST(Default3D); + MITK_TEST(Color3D); + MITK_TEST(Ribbon3D); + MITK_TEST(Tubes3D); + MITK_TEST(Default2D); CPPUNIT_TEST_SUITE_END(); typedef itk::Image ItkFloatImgType; private: /** Members used inside the different (sub-)tests. All members are initialized via setUp().*/ mitk::FiberBundle::Pointer fib; + mitk::DataNode::Pointer node; public: void setUp() override { - fib = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberFit/Cluster_0.fib")); + fib = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/Rendering/test_fibers.fib")); + MITK_INFO << fib->GetNumFibers(); + node = mitk::DataNode::New(); + node->SetData(fib); } void tearDown() override { } void AddGeneratedDataToStorage(mitk::DataStorage *dataStorage) { auto node = mitk::DataNode::New(); node->SetData(fib); dataStorage->Add(node); } - void Test1() + void Default2D() { - omp_set_num_threads(1); + mitk::RenderingTestHelper renderingHelper(640, 480); + renderingHelper.AddNodeToStorage(node); + renderingHelper.SetViewDirection(mitk::SliceNavigationController::Frontal); + renderingHelper.SetMapperIDToRender2D(); - auto node = mitk::DataNode::New(); - node->SetData(fib); + renderingHelper.SaveReferenceScreenShot(mitk::IOUtil::GetTempPath()+"fib_2D.png"); + mitk::Image::Pointer test_image = mitk::IOUtil::Load(mitk::IOUtil::GetTempPath()+"fib_2D.png"); + mitk::Image::Pointer ref_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/Rendering/fib_2D.png")); + MITK_ASSERT_EQUAL(test_image, ref_image, "Check if images are equal."); + } + void Default3D() + { mitk::RenderingTestHelper renderingHelper(640, 480); renderingHelper.AddNodeToStorage(node); + renderingHelper.SetMapperIDToRender3D(); - renderingHelper.SetMapperID(mitk::BaseRenderer::Standard3D); - renderingHelper.GetVtkRenderer()->SetBackground(0.0, 0.0, 0.0); + renderingHelper.SaveReferenceScreenShot(mitk::IOUtil::GetTempPath()+"fib_3D.png"); + mitk::Image::Pointer test_image = mitk::IOUtil::Load(mitk::IOUtil::GetTempPath()+"fib_3D.png"); + mitk::Image::Pointer ref_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/Rendering/fib_3D.png")); + MITK_ASSERT_EQUAL(test_image, ref_image, "Check if images are equal."); + } - mitk::RenderingManager::GetInstance()->InitializeViews(fib->GetGeometry(), mitk::RenderingManager::RequestType::REQUEST_UPDATE_ALL); - renderingHelper.SaveReferenceScreenShot(mitk::IOUtil::GetTempPath()+"fib_renderingtest.png"); - -// MITK_INFO << "1"; -// char* argv[4]; -// argv[0] = (char*)""; -// argv[1] = (char*)""; -// argv[1] = (char*)"-V"; -// argv[3] = (char*)GetTestDataFilePath("fib_renderingtest.png").c_str(); -// MITK_INFO << "2"; -// CPPUNIT_ASSERT_MESSAGE("CompareRenderWindowAgainstReference test result positive?", renderingHelper.CompareRenderWindowAgainstReference(4, argv)); + void Tubes3D() + { + node->SetBoolProperty( "light.enable_light", true); + node->SetFloatProperty("shape.tuberadius", 1); + + mitk::RenderingTestHelper renderingHelper(640, 480); + renderingHelper.AddNodeToStorage(node); + renderingHelper.SetMapperIDToRender3D(); + + renderingHelper.SaveReferenceScreenShot(mitk::IOUtil::GetTempPath()+"fib_tubes_3D.png"); + mitk::Image::Pointer test_image = mitk::IOUtil::Load(mitk::IOUtil::GetTempPath()+"fib_tubes_3D.png"); + mitk::Image::Pointer ref_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/Rendering/fib_tubes_3D.png")); + MITK_ASSERT_EQUAL(test_image, ref_image, "Check if images are equal."); + } + + void Ribbon3D() + { + node->SetBoolProperty( "light.enable_light", true); + node->SetFloatProperty("shape.ribbonwidth", 1); + + mitk::RenderingTestHelper renderingHelper(640, 480); + renderingHelper.AddNodeToStorage(node); + renderingHelper.SetMapperIDToRender3D(); + + renderingHelper.SaveReferenceScreenShot(mitk::IOUtil::GetTempPath()+"fib_ribbon_3D.png"); + mitk::Image::Pointer test_image = mitk::IOUtil::Load(mitk::IOUtil::GetTempPath()+"fib_ribbon_3D.png"); + mitk::Image::Pointer ref_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/Rendering/fib_ribbon_3D.png")); + MITK_ASSERT_EQUAL(test_image, ref_image, "Check if images are equal."); + } + + void Line3D() + { + node->SetFloatProperty("shape.linewidth", 1); + + mitk::RenderingTestHelper renderingHelper(640, 480); + renderingHelper.AddNodeToStorage(node); + renderingHelper.SetMapperIDToRender3D(); + + renderingHelper.SaveReferenceScreenShot(mitk::IOUtil::GetTempPath()+"fib_line_3D.png"); + mitk::Image::Pointer test_image = mitk::IOUtil::Load(mitk::IOUtil::GetTempPath()+"fib_line_3D.png"); + mitk::Image::Pointer ref_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/Rendering/fib_line_3D.png")); + MITK_ASSERT_EQUAL(test_image, ref_image, "Check if images are equal."); } + void Color3D() + { + mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); + fib->SetFiberColors(255, 255, 255); + + mitk::RenderingTestHelper renderingHelper(640, 480); + renderingHelper.AddNodeToStorage(node); + renderingHelper.SetMapperIDToRender3D(); + renderingHelper.GetVtkRenderer()->SetBackground(0.0, 0.0, 0.0); + + renderingHelper.SaveReferenceScreenShot(mitk::IOUtil::GetTempPath()+"fib_color_3D.png"); + mitk::Image::Pointer test_image = mitk::IOUtil::Load(mitk::IOUtil::GetTempPath()+"fib_color_3D.png"); + mitk::Image::Pointer ref_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/Rendering/fib_color_3D.png")); + MITK_ASSERT_EQUAL(test_image, ref_image, "Check if images are equal."); + } }; MITK_TEST_SUITE_REGISTRATION(mitkFiberMapper3D) diff --git a/Modules/OpenCL/mitkOpenCL.h b/Modules/OpenCL/mitkOpenCL.h index a0147b238b..d2131a3455 100644 --- a/Modules/OpenCL/mitkOpenCL.h +++ b/Modules/OpenCL/mitkOpenCL.h @@ -1,26 +1,27 @@ /*=================================================================== 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 MITKOPENCL_H_HEADER_INCLUDED #define MITKOPENCL_H_HEADER_INCLUDED #if defined (__APPLE__) || defined(MACOSX) #include #else +#define CL_USE_DEPRECATED_OPENCL_1_2_APIS #include #endif #endif /* MITKOPENCL_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticFilterService.cpp b/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticFilterService.cpp index 7bbcfa790b..4e11f43d2d 100644 --- a/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticFilterService.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticFilterService.cpp @@ -1,502 +1,502 @@ /*=================================================================== 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 "mitkPhotoacousticFilterService.h" #include "../ITKFilter/ITKUltrasound/itkBModeImageFilter.h" #include "../ITKFilter/itkPhotoacousticBModeImageFilter.h" #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include "mitkPhotoacousticBeamformingFilter.h" #include #include #include #include "./OpenCLFilter/mitkPhotoacousticBModeFilter.h" #include "mitkConvert2Dto3DImageFilter.h" // itk dependencies #include "itkImage.h" #include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "itkCropImageFilter.h" #include "itkRescaleIntensityImageFilter.h" #include "itkIntensityWindowingImageFilter.h" #include #include "itkMultiplyImageFilter.h" #include "itkBSplineInterpolateImageFunction.h" #include // needed itk image filters #include "mitkITKImageImport.h" #include "itkFFTShiftImageFilter.h" #include "itkMultiplyImageFilter.h" #include "itkComplexToModulusImageFilter.h" #include #include "../ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h" #include "../ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h" mitk::PhotoacousticFilterService::PhotoacousticFilterService() { MITK_INFO << "[PhotoacousticFilterService] created filter service"; } mitk::PhotoacousticFilterService::~PhotoacousticFilterService() { MITK_INFO << "[PhotoacousticFilterService] destructed filter service"; } mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method, bool UseGPU, bool UseLogFilter, float resampleSpacing) { // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::IdentityTransform TransformType; if (method == BModeMethod::Abs) { mitk::Image::Pointer input; mitk::Image::Pointer out; if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") input = inputImage; else input = ApplyCropping(inputImage, 0, 0, 0, 0, 0, inputImage->GetDimension(2) - 1); if (!UseGPU) { PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); filter->SetParameters(UseLogFilter); filter->SetInput(input); filter->Update(); out = filter->GetOutput(); if (resampleSpacing == 0) return out; } #ifdef PHOTOACOUSTICS_USE_GPU else { PhotoacousticOCLBModeFilter::Pointer filter = PhotoacousticOCLBModeFilter::New(); filter->SetParameters(UseLogFilter); filter->SetInput(input); filter->Update(); out = filter->GetOutput(); if (resampleSpacing == 0) return out; } #endif typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(out, itkImage); itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; outputSpacing[0] = itkImage->GetSpacing()[0]; outputSpacing[1] = resampleSpacing; outputSpacing[2] = itkImage->GetSpacing()[2]; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; typedef itk::IdentityTransform TransformType; resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSize); resampleImageFilter->SetOutputSpacing(outputSpacing); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } else if (method == BModeMethod::EnvelopeDetection) { typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); itkFloatImageType::Pointer bmode; if (UseLogFilter) { bModeFilter->SetInput(itkImage); bModeFilter->SetDirection(1); bmode = bModeFilter->GetOutput(); } else { photoacousticBModeFilter->SetInput(itkImage); photoacousticBModeFilter->SetDirection(1); bmode = photoacousticBModeFilter->GetOutput(); } // resampleSpacing == 0 means: do no resampling if (resampleSpacing == 0) { return mitk::GrabItkImageMemory(bmode); } itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; outputSpacing[0] = itkImage->GetSpacing()[0]; outputSpacing[1] = resampleSpacing; outputSpacing[2] = itkImage->GetSpacing()[2]; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; resampleImageFilter->SetInput(bmode); resampleImageFilter->SetSize(outputSize); resampleImageFilter->SetOutputSpacing(outputSpacing); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } return nullptr; } mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]) { typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); typedef itk::LinearInterpolateImageFunction T_Interpolator; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); itkFloatImageType::SpacingType outputSpacingItk; itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSizeItk = inputSizeItk; outputSizeItk[0] = outputSize[0]; outputSizeItk[1] = outputSize[1]; outputSizeItk[2] = inputSizeItk[2]; outputSpacingItk[0] = itkImage->GetSpacing()[0] * (static_cast(inputSizeItk[0]) / static_cast(outputSizeItk[0])); outputSpacingItk[1] = itkImage->GetSpacing()[1] * (static_cast(inputSizeItk[1]) / static_cast(outputSizeItk[1])); outputSpacingItk[2] = itkImage->GetSpacing()[2]; typedef itk::IdentityTransform TransformType; T_Interpolator::Pointer _pInterpolator = T_Interpolator::New(); resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSizeItk); resampleImageFilter->SetOutputSpacing(outputSpacingItk); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->SetInterpolator(_pInterpolator); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice) { unsigned int inputDim[3] = { inputImage->GetDimension(0), inputImage->GetDimension(1), inputImage->GetDimension(2) }; unsigned int outputDim[3] = { inputImage->GetDimension(0) - left - right, inputImage->GetDimension(1) - (unsigned int)above - (unsigned int)below, (unsigned int)maxSlice - (unsigned int)minSlice + 1 }; void* inputData; float* outputData = new float[outputDim[0] * outputDim[1] * outputDim[2]]; ImageReadAccessor acc(inputImage); inputData = const_cast(acc.GetData()); // convert the data to float by default // as of now only float, short, double are used at all. if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") { // copy the data into the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((float*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (short)" || inputImage->GetPixelType().GetTypeAsString() == " (short)") { // copy the data to the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((short*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (double)" || inputImage->GetPixelType().GetTypeAsString() == " (double)") { // copy the data to the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((double*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else { MITK_INFO << "Could not determine pixel type"; } mitk::Image::Pointer output = mitk::Image::New(); output->Initialize(mitk::MakeScalarPixelType(), 3, outputDim); output->SetSpacing(inputImage->GetGeometry()->GetSpacing()); - output->SetImportVolume(outputData, 0, 0, mitk::Image::ReferenceMemory); - + output->SetImportVolume(outputData, 0, 0, mitk::Image::CopyMemory); + delete[] outputData; return output; } mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings::Pointer config, std::string& message, std::function progressHandle) { Image::Pointer processedImage = mitk::Image::New(); if (inputImage->GetDimension() != 3) { mitk::Convert2Dto3DImageFilter::Pointer dimensionImageFilter = mitk::Convert2Dto3DImageFilter::New(); dimensionImageFilter->SetInput(inputImage); dimensionImageFilter->Update(); processedImage = dimensionImageFilter->GetOutput(); } //config->SetRecordTime(config->GetRecordTime() - (float)(config->GetUpperCutoff()) / // (float)inputImage->GetDimension(1) * config->GetRecordTime()); // adjust the recorded time lost by cropping //progressHandle(0, "converting image"); //if (!config->GetPartial()) //{ // config->GetCropBounds()[0] = 0; // config->GetCropBounds()[1] = inputImage->GetDimension(2) - 1; //} //processedImage = ApplyCropping(inputImage, config->GetUpperCutoff(), 0, 0, 0, config->GetCropBounds()[0], config->GetCropBounds()[1]); config->GetInputDim()[0] = processedImage->GetDimension(0); config->GetInputDim()[1] = processedImage->GetDimension(1); config->GetInputDim()[2] = processedImage->GetDimension(2); // perform the beamforming m_BeamformingFilter = mitk::BeamformingFilter::New(config); m_BeamformingFilter->SetInput(processedImage); m_BeamformingFilter->SetProgressHandle(progressHandle); m_BeamformingFilter->UpdateLargestPossibleRegion(); processedImage = m_BeamformingFilter->GetOutput(); message = m_BeamformingFilter->GetMessageString(); return processedImage; } mitk::Image::Pointer mitk::PhotoacousticFilterService::BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alphaHighPass, float alphaLowPass) { bool powerOfTwo = false; int finalPower = 0; for (int i = 1; pow(2, i) <= data->GetDimension(1); ++i) { finalPower = i; if (pow(2, i) == data->GetDimension(1)) { powerOfTwo = true; } } if (!powerOfTwo) { unsigned int dim[2] = { data->GetDimension(0), (unsigned int)pow(2,finalPower + 1) }; data = ApplyResampling(data, dim); } MITK_INFO << data->GetDimension(0); // do a fourier transform, multiply with an appropriate window for the filter, and transform back typedef float PixelType; typedef itk::Image< PixelType, 3 > RealImageType; RealImageType::Pointer image; mitk::CastToItkImage(data, image); typedef itk::FFT1DRealToComplexConjugateImageFilter ForwardFFTFilterType; typedef ForwardFFTFilterType::OutputImageType ComplexImageType; ForwardFFTFilterType::Pointer forwardFFTFilter = ForwardFFTFilterType::New(); forwardFFTFilter->SetInput(image); forwardFFTFilter->SetDirection(1); try { forwardFFTFilter->UpdateOutputInformation(); } catch (itk::ExceptionObject & error) { std::cerr << "Error: " << error << std::endl; MITK_WARN << "Bandpass could not be applied"; return data; } float singleVoxel = 1 / (recordTime / data->GetDimension(1)) / 2 / 1000; float cutoffPixelHighPass = std::min(BPHighPass / singleVoxel, (float)data->GetDimension(1) / 2); float cutoffPixelLowPass = std::min(BPLowPass / singleVoxel, (float)data->GetDimension(1) / 2 - cutoffPixelHighPass); RealImageType::Pointer fftMultiplicator = BPFunction(data, cutoffPixelHighPass, cutoffPixelLowPass, alphaHighPass, alphaLowPass); typedef itk::MultiplyImageFilter< ComplexImageType, RealImageType, ComplexImageType > MultiplyFilterType; MultiplyFilterType::Pointer multiplyFilter = MultiplyFilterType::New(); multiplyFilter->SetInput1(forwardFFTFilter->GetOutput()); multiplyFilter->SetInput2(fftMultiplicator); /*itk::ComplexToModulusImageFilter::Pointer toReal = itk::ComplexToModulusImageFilter::New(); toReal->SetInput(forwardFFTFilter->GetOutput()); return GrabItkImageMemory(toReal->GetOutput()); return GrabItkImageMemory(fftMultiplicator); *///DEBUG typedef itk::FFT1DComplexConjugateToRealImageFilter< ComplexImageType, RealImageType > InverseFilterType; InverseFilterType::Pointer inverseFFTFilter = InverseFilterType::New(); inverseFFTFilter->SetInput(multiplyFilter->GetOutput()); inverseFFTFilter->SetDirection(1); return GrabItkImageMemory(inverseFFTFilter->GetOutput()); } itk::Image::Pointer mitk::PhotoacousticFilterService::BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alphaHighPass, float alphaLowPass) { float* imageData = new float[reference->GetDimension(0)*reference->GetDimension(1)]; float width = reference->GetDimension(1) / 2.0 - (float)cutoffFrequencyPixelHighPass - (float)cutoffFrequencyPixelLowPass; float center = (float)cutoffFrequencyPixelHighPass / 2.0 + width / 2.0; for (unsigned int n = 0; n < reference->GetDimension(1); ++n) { imageData[reference->GetDimension(0)*n] = 0; } for (int n = 0; n < width; ++n) { imageData[reference->GetDimension(0)*n] = 1; if (n <= (alphaHighPass*(width - 1)) / 2.0) { if (alphaHighPass > 0.00001) { imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(itk::Math::pi*(2 * n / (alphaHighPass*(width - 1)) - 1))) / 2; } else { imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; } } else if (n >= (width - 1)*(1 - alphaLowPass / 2)) //??? { if (alphaLowPass > 0.00001) { imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(itk::Math::pi*(2 * n / (alphaLowPass*(width - 1)) + 1 - 2 / alphaLowPass))) / 2; } else { imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; } } //MITK_INFO << "n:" << n << " is " << imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))]; } MITK_INFO << "width: " << width << ", center: " << center << ", alphaHighPass: " << alphaHighPass << ", alphaLowPass: " << alphaLowPass; // mirror the first half of the image for (unsigned int n = reference->GetDimension(1) / 2; n < reference->GetDimension(1); ++n) { imageData[reference->GetDimension(0)*n] = imageData[(reference->GetDimension(1) - (n + 1)) * reference->GetDimension(0)]; } // copy and paste to all lines for (unsigned int line = 1; line < reference->GetDimension(0); ++line) { for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) { imageData[reference->GetDimension(0)*sample + line] = imageData[reference->GetDimension(0)*sample]; } } typedef itk::Image< float, 3U > ImageType; ImageType::RegionType region; ImageType::IndexType start; start.Fill(0); region.SetIndex(start); ImageType::SizeType size; size[0] = reference->GetDimension(0); size[1] = reference->GetDimension(1); size[2] = reference->GetDimension(2); region.SetSize(size); ImageType::SpacingType SpacingItk; SpacingItk[0] = reference->GetGeometry()->GetSpacing()[0]; SpacingItk[1] = reference->GetGeometry()->GetSpacing()[1]; SpacingItk[2] = reference->GetGeometry()->GetSpacing()[2]; ImageType::Pointer image = ImageType::New(); image->SetRegions(region); image->Allocate(); image->FillBuffer(itk::NumericTraits::Zero); image->SetSpacing(SpacingItk); ImageType::IndexType pixelIndex; for (unsigned int slice = 0; slice < reference->GetDimension(2); ++slice) { for (unsigned int line = 0; line < reference->GetDimension(0); ++line) { for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) { pixelIndex[0] = line; pixelIndex[1] = sample; pixelIndex[2] = slice; image->SetPixel(pixelIndex, imageData[line + sample*reference->GetDimension(0)]); } } } delete[] imageData; return image; } diff --git a/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox b/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox index 06afcb812e..1487cb3947 100644 --- a/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox +++ b/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox @@ -1,16 +1,16 @@ /** \page org_blueberry_ui_qt_log The Logging Plugin -\imageMacro{Logging.png,"Icon of the Logging Plugin",2.00} +\imageMacro{logging.svg,"Icon of the Logging Plugin",2.00} This plug-in records all logging output of events and progress as specified in the source code with time of occurence, level of importance (Info, Warning, Error, Fatal, Debug), the message given and where it happens. The logging starts once the plug-is started. A screenshot of the provided Logging view is shown next. \imageMacro{LogView.png,"Screenshot of the Logging Module",16.00} There are different features available in the view. The filter text field allows for searching all log events containing a certain substring. Using the button "Copy to clipboard" on the bottom right you can copy the current content of the logging view to your clipboard. This enables you to insert the logging information to any text processing application. You can also show more information on every logging message by activating the two checkboxes. In the simple view, leaving both checkboxes unchecked, you'll see logging messages and logging levels. A brief description of the logging levels can be found in the \ref LoggingPage "logging concept documentation". The checkbox "Category" adds a column for the category. The checkbox "Show Advanced Field" shows method, filename and linenumber where the logging message was emitted as well as the running time of the application. The next figure shows all information which can be shown in the Logging Module. \imageMacro{LogViewExplain.png,"Details on the Vizualized Logging Information",16.00} */ diff --git a/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/logging.svg b/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/logging.svg new file mode 100644 index 0000000000..ccb549f8a6 --- /dev/null +++ b/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/logging.svg @@ -0,0 +1,80 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.cest/plugin.xml b/Plugins/org.mitk.gui.qt.cest/plugin.xml index 2638bf6838..e44ea5da6e 100644 --- a/Plugins/org.mitk.gui.qt.cest/plugin.xml +++ b/Plugins/org.mitk.gui.qt.cest/plugin.xml @@ -1,11 +1,12 @@ + icon="resources/icon.svg" + category="CEST"/> diff --git a/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox b/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox index 09ce1a4f48..08e636a260 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox +++ b/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox @@ -1,109 +1,109 @@ /** \page org_mitk_views_datamanager The DataManager -\imageMacro{QmitkDatamanager_Icon.png,"Icon of the Data Manager",2.00} +\imageMacro{data-manager.svg,"Icon of the Data Manager",2.00} \tableofcontents \section QmitkDataManagerIntroduction Introduction The Datamanager is the central componenent to manage medical data like images, surfaces, etc.. After loading one or more data into the Datamanager the data are shown in the four-view window, the so called Standard View. The user can now start working on the data by just clicking into the standard view or by using the MITK-modules such as "Segmentation" or "Basic Image Processing". \imageMacro{QmitkDatamanager_Overview.png,"How MITK looks when started",16.00} \section QmitkDataManagerLoading Loading Data There are three ways of loading data into the Datamanager as so called Data-Elements. The user can just drag and drop data into the Datamanager or directly into one of the four parts of the Standard View. He can as well use the Open-Button in the right upper corner. Or he can use the standard "File->Open"-Dialog on the top. A lot of file-formats can be loaded into MITK, for example
  • 2D-images/3D-volumes with or without several timesteps (*.dcm, *.ima, *.pic, ...)
  • Surfaces (*.stl, *.vtk, ...)
  • Pointsets (*.mps)
  • ...
The user can also load a series of 2D images (e.g. image001.png, image002.png ...) to a MITK 3D volume. To do this, just drag and drop one of those 2D data files into the Datamanager by holding the ALT key. After loading one or more data into the Datamanager they appear as Data-Elements in a sorted list inside the Datamanager. Data-Elements can also be sorted hierarchically as a parent-child-relation. For example after using the Segmentation-Module on Data-Element1 the result is created as Data-Element2, which is a child of Data-Element1 (see Screenshot1). The order can be changed by drag and drop. \imageMacro{QmitkDatamanager_ParentChild.png,"Screenshot1",9.61} The listed Data-Elements are shown in the standard view. Here the user can scale or rotate the medical objects or he can change the cutting planes of the object by just using the mouse inside this view. \section QmitkDataManagerSaving Saving Data There are two ways of saving data from the Datamanger. The user can either save the whole project with all Data-Elements by clicking on "File"->"Save Project" or he can save single Data-Elements by right-clicking->"Save", directly on a Data-Element. When saving the whole project, the sorting of Data-Elements is saved as well. By contrast the sorting is lost, when saving a single Data-Element. \section QmitkDataManagerProperties Working with the Datamanager \subsection QmitkDataManagerPropertiesList List of Data-Elements The Data-Elements are listed in the Datamanager. As described above the elements can be sorted hierarchically as a parent-child-relation. For example after using the Segmentation-Module on Data-Element1 the result is created as Data-Element2, which is a child of Data-Element1 (see Screenshot1). By drag and drop the sorting of Data-Elements and their hierarchical relation can be changed. \subsection QmitkDataManagerPropertiesVisibility Visibility of Data-Elements By default all loaded Data-Elements are visible in the standard view. The visibility can be changed by right-clicking on the Data-Element and then choosing "Toogle visibility". The box in front of the Data-Element in the Datamanager shows the visibility. A green-filled box means a visible Data-Element, an empty box means an invisible Data-Element (see Screenshot1). \subsection QmitkDataManagerPropertiesRepresentation Representation of Data-Elements There are different types of representations how to show the Data-Element inside the standard view. By right-clicking on the Data-Element all options are listed (see Screenshot2 and Screenshot 3).
  • An arbitrary color can be chosen
  • The opacity can be changed with a slide control
  • In case of images a texture interpolation can be switched on or off. The texture interpolation smoothes the image, so that no single pixels are visible anymore.
  • In case of surfaces the surface representation can be changed between points, wireframe or surface.
  • Global reinit updates all windows to contain all the current data: - The orientation of the worldgeometry, which basically defines the rendering space, is set to the standard coordinate system, i.e. [(0,0,1);(0,1,0);(0,0,1)] - The size of the worldgeometry is calculated, so that it includes all loaded data (depends on size and position of your data) - The spacing is set to the smallest existing spacing regarding your data Reinit updates a single data item and fits the windows to contain only this data item: - The orientation of the worldgeometry, is aligned according to the orientation of the currently selected datanode - The size of the worldgeometry is set to the size of the currently selected datanode - The spacing is set to the spacing of the currently selected datanode
\imageMacro{QmitkDatamanager_ImageProperties.png,"Screenshot2: Properties for images",10.56} \imageMacro{QmitkDatamanager_SurfaceProperties.png,"Screenshot3: Properties for surfaces",11.01} \subsection QmitkDataManagerPropertiesPreferences Preferences For the datamanager there are already some default hotkeys like the del-key for deleting a Data-Element. The whole list is seen in Screenshot4. From here the Hotkeys can also be changed. The preference page is found in "Window"->"Preferences". \imageMacro{QmitkDatamanager_Preferences.png,"Screenshot4",16.00} \section QmitkDataManagerPropertyList Property List The Property List displays all the properties the currently selected Data-Element has. Which properties these are depends on the Data-Element. Examples are opacity, shader, visibility. These properties can be changed by clicking on the appropriate field in the "value" column. \imageMacro{QmitkDatamanager_PropertyList.png,"Screenshot5: Property List",7.85} */ diff --git a/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/data-manager.svg b/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/data-manager.svg new file mode 100644 index 0000000000..7dd5c797d5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/data-manager.svg @@ -0,0 +1,60 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/QmitkDicom.dox b/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/QmitkDicom.dox index fb81cee2d4..136c56e93d 100644 --- a/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/QmitkDicom.dox +++ b/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/QmitkDicom.dox @@ -1,118 +1,118 @@ /** \page org_mitk_gui_qt_dicom The Dicom Plugin -\imageMacro{QmitkDicom_Icon.png,"Icon of the DICOM Plugin",2.00} +\imageMacro{dicom.svg,"Icon of the DICOM Plugin",2.00} \note This article requires a basic knowledge of the DICOM Standard. \tableofcontents \section org_mitk_gui_qt_dicomOverview Overview The DICOM editor is an experimental editor which allows for loading of DICOM images as well as server communication. It features a highly experimental query/retrieve (you need to configure your PACS correspondingly) as well as a DICOM browser. The DICOM browser allows you to navigate the DICOM folder/cd depending on its metadata (patient/study/series) and import selected series for viewing in your MITK based application. It also allows you to store your dicom data in an internal database so you can easily access often used dicom images. It is based on the commonTK (CTK) DICOM funcionality. \section org_mitk_gui_qt_dicomDataHandling Data handling \imageMacro{QmitkDicom_PluginControls.png,"The dicom Plugin controls",7.37} In the image above you see the start page of the dicom plugin. On top of the start page you see four buttons. The Local Storage, the Import CD, the Import Folder and the Query Retrieve button. If you press one of these buttons, the dicom plugin will switch to your local dicom image storage or will start importing dicom images from CD or a folder on your hard drive or it will open the query retrieve screen.
  • Click the 'Local Storage' button to open the local storage screen.
  • Click the 'Import CD' button to import DICOM data from a CD.
  • Click the 'Import Folder' button to import DICOM date from a directory.
  • Click the 'Query Retrieve' button to open the query retrieve screen.
\subsection org_mitk_gui_qt_dicomStorage Data storage \imageMacro{QmitkDicom_PluginExtended.png,"The DICOM data storage",16.00} If you open the dicom plugin the dicom data storage will be displayed. You are able to see all your stored dicom image data. You can browse your data by clicking on the left arrow beside the name of your data. There are three levels available. The first level is the patient level where you can see the patient data. On the second level you can see the dicom studies for the patient. on the third level you can see all available series refering to it's study. You can delete the data by selecting it and pressing the delete button. Be careful if you have selected a patient or a study all refering data be deleted. So if you delete a patient the patient and all studies and series refered to the patient will be deleted. If you delete a study all series of the study will be deleted. If you want to view the dicom data you have to select a series and click on the View button. The data will appear in the DataManager and will be dispayed. \imageMacro{QmitkDicom_DisplayDataManager.png,"Viewed image",16.00}
  • Click on the arrow on the left of your data to expand or hide dicom data levels.
  • Click the 'Delete' button to delete selected DICOM data.
  • Click the 'View' button to view DICOM data.
\subsection org_mitk_gui_qt_dicomImport Data import \imageMacro{QmitkDicom_ImportDialog.png,"The import dialog checked",9.53} There are two diffrent ways to import DICOM data. The First one is to directly imort it into your DICOM data storage. To achieve this you should toggle the checkbox 'Copy on import'. The second approach is, to have a look at the data first before importing it. To do that you simply don't check 'Copy on import'. This will leed you to the leed you to the 'External Dicom Data' screen which provides you a preview of the data containing in youre choosen folder. You can import the data here by selecting it and pressing the 'Download' button. It is also possible to view DICOM series directly in Mitk by selecting it here and pressing the 'View' button.
  • Click 'Import Folder' or 'Import CD' button to open the import dialog.
    • Enable the 'Copy on import' checkbox and choose a folder to import into data storage directly.
    • Disable the 'Copy on import' checkbox to get to the 'External Dicom Data' screen.
      • Click on the arrow on the left of your data to expand or hide dicom data levels.
      • Click the 'Download' button to download selected DICOM data to your DICOM data storage.
      • Click the 'View' button to view DICOM data.
\section org_mitk_gui_qt_dicomQueryRetrieve Query/Retrieve \warning This plugin is experimental and not all of the described features behave as expected. \note The query retrieve plugin only works if the PACS you are calling knows your machine settings. There are also issues when you are running a firewall. The query retrieve workflow allows you to get DICOM data from a server. \imageMacro{QmitkDicom_QueryRetrieve.png,"The query retrieve screen",16.00} \subsection org_mitk_gui_qt_dicomQuery Query \imageMacro{QmitkDicom_Nodes.png,"The DICOM network configuration",11.26} By performing a DICOM query you will ask a server for it's DICOM data. This requires to setup the DICOM network configuration of your system and the server. By clicking on 'Add Server' a new plain server field will appear. Now you can give it a name of your choice. Fill the servers "DICOM name" the AETitle. Type in it's url, it's port and the specific DICOM protocoll you want to use for image transfer. \note I recommend not to use CGET because most of the PACS systems (Image Servers) don't support that protocoll. You can configure the DICOM network configuration of your machine by editing the 'Calling AETiltle', the 'Storage AETitle' and The 'Storage Port' text fields. But normaly you don't have to change your configuration. \imageMacro{QmitkDicom_FilterWidget.png,"The DICOM search options",3.66} After you have finished your network configuration and before you start the query you should use the 'Search Options' to specify your query. Otherwise all data on the server will be queried and you will have to wait for a long time. You can specify your query by searching for a specific patient name or a study or a serie or a specific DICOM object by it's id. You are allowed to include or exclude DICOM modalities from your query and you can specify a specific time in which the DICOM images you are searching fo might been captured. When you finished that you can click the query button and the queried DICOM data will appear.
  • Click on the 'Add Server' button.
    • Edit 'Name' field.
    • Edit 'AETitle' field.
    • Edit 'Adress' field.
    • Edit 'Port' field.
  • Set search options.
  • Click on 'Query' button.
\subsection org_mitk_gui_qt_dicomRetrieve Retrieve \imageMacro{QmitkDicom_Retrieve.png,"The queried DICOM data.",15.22} After the query you are able to select the queried data and click the 'Retrieve' button. This will store the queried DICOM data into your DICOM storage. Click on the 'Local Storage' button and work with your new data.
  • Click on the 'Retrieve' button to retrieve the data to your DICOM storage.
  • Click on the 'Local Storage' button.
*/ diff --git a/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/dicom.svg b/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/dicom.svg new file mode 100644 index 0000000000..3d10f794ae --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/dicom.svg @@ -0,0 +1,85 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/QmitkODFRenderWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/QmitkODFRenderWidget.cpp index 8fe3c644ac..2fd0f35086 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/QmitkODFRenderWidget.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/QmitkODFRenderWidget.cpp @@ -1,123 +1,123 @@ /*=================================================================== 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 "QmitkODFRenderWidget.h" #include #include #include #include QmitkODFRenderWidget::QmitkODFRenderWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) { //create Layouts QmitkODFRenderWidgetLayout = new QHBoxLayout( this ); //Set Layout to widget this->setLayout(QmitkODFRenderWidgetLayout); //Create RenderWindow m_RenderWindow = new QmitkRenderWindow(this, "odf render widget"); m_RenderWindow->setMaximumSize(300,300); m_RenderWindow->GetRenderer()->SetMapperID( mitk::BaseRenderer::Standard3D ); //m_RenderWindow->SetLayoutIndex( 3 ); QmitkODFRenderWidgetLayout->addWidget( m_RenderWindow ); } QmitkODFRenderWidget::~QmitkODFRenderWidget() { } void QmitkODFRenderWidget::GenerateODF( itk::OrientationDistributionFunction odf ) { try { m_Surface = mitk::Surface::New(); m_ds = mitk::StandaloneDataStorage::New(); m_Node = mitk::DataNode::New(); vtkPolyData* m_TemplateOdf = itk::OrientationDistributionFunction::GetBaseMesh(); vtkPolyData *polyData = vtkPolyData::New(); vtkPoints *points = vtkPoints::New(); vtkFloatArray *scalars = vtkFloatArray::New(); for (int i=0; iGetPoints()->GetPoint(i,p); double val = odf[i]; p[0] *= val; p[1] *= val; p[2] *= val; points->InsertPoint(i,p); scalars->InsertTuple1(i, 1-val); } polyData->SetPoints(points); vtkCellArray* polys = m_TemplateOdf->GetPolys(); polyData->SetPolys(polys); polyData->GetPointData()->SetScalars(scalars); polys->Delete(); scalars->Delete(); points->Delete(); m_Surface->SetVtkPolyData(polyData); m_Node->SetData(m_Surface); mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); // assign an empty vtk lookup table to the odf renderer, it is the same // the ODF 2D Mapper has - vtkLookupTable *lut = vtkLookupTable::New(); + vtkSmartPointer lut = vtkSmartPointer::New(); mitkLut->SetVtkLookupTable( lut ); mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); mitkLutProp->SetLookupTable(mitkLut); m_Node->SetProperty( "LookupTable", mitkLutProp ); m_Node->SetProperty("scalar visibility", mitk::BoolProperty::New(true)); m_Node->SetProperty("color mode", mitk::BoolProperty::New(true)); m_Node->SetProperty("material.specularCoefficient", mitk::FloatProperty::New(0.5)); m_ds->Add(m_Node); m_RenderWindow->GetRenderer()->SetDataStorage( m_ds ); // adjust camera to current plane rotation mitk::PlaneGeometry::ConstPointer worldPlaneGeometry = mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow())->GetCurrentWorldPlaneGeometry(); mitk::Vector3D normal = worldPlaneGeometry->GetNormal(); mitk::Vector3D up = worldPlaneGeometry->GetAxisVector(1); normal.Normalize(); up.Normalize(); vtkSmartPointer cam = vtkSmartPointer::New(); const double camPos[3] = {normal[0],normal[1],normal[2]}; const double camUp[3] = {up[0],up[1],up[2]}; cam->SetPosition(camPos); cam->SetViewUp(camUp); cam->SetParallelProjection(1); m_RenderWindow->GetRenderer()->GetVtkRenderer()->SetActiveCamera(cam); m_RenderWindow->update(); } catch (...) { } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp index 4877541e23..ffb42eadcd 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp @@ -1,971 +1,1019 @@ /*=================================================================== 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 #include // Qmitk #include "QmitkStreamlineTrackingView.h" #include "QmitkStdMultiWidget.h" // Qt #include // MITK #include #include #include #include #include #include #include #include #include #include #include #include #include // VTK #include #include #include #include #include #include #include #include #include +#include const std::string QmitkStreamlineTrackingView::VIEW_ID = "org.mitk.views.streamlinetracking"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace berry; QmitkStreamlineTrackingWorker::QmitkStreamlineTrackingWorker(QmitkStreamlineTrackingView* view) : m_View(view) { } void QmitkStreamlineTrackingWorker::run() { m_View->m_Tracker->Update(); m_View->m_TrackingThread.quit(); } QmitkStreamlineTrackingView::QmitkStreamlineTrackingView() : m_TrackingWorker(this) , m_Controls(nullptr) , m_FirstTensorProbRun(true) , m_FirstInteractiveRun(true) , m_TrackingHandler(nullptr) , m_ThreadIsRunning(false) , m_DeleteTrackingHandler(false) , m_Visible(false) , m_LastPrior("") , m_TrackingPriorHandler(nullptr) { m_TrackingWorker.moveToThread(&m_TrackingThread); connect(&m_TrackingThread, SIGNAL(started()), this, SLOT(BeforeThread())); connect(&m_TrackingThread, SIGNAL(started()), &m_TrackingWorker, SLOT(run())); connect(&m_TrackingThread, SIGNAL(finished()), this, SLOT(AfterThread())); m_TrackingTimer = new QTimer(this); } // Destructor QmitkStreamlineTrackingView::~QmitkStreamlineTrackingView() { if (m_Tracker.IsNull()) return; m_Tracker->SetStopTracking(true); m_TrackingThread.wait(); } void QmitkStreamlineTrackingView::CreateQtPartControl( QWidget *parent ) { if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkStreamlineTrackingViewControls; m_Controls->setupUi( parent ); m_Controls->m_FaImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_SeedImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TargetImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_PriorImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_StopImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ForestBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ExclusionImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isPeakImagePredicate = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isTractographyForest = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New( isBinaryPredicate ); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New( isImagePredicate, isNotBinaryPredicate ); mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); m_Controls->m_ForestBox->SetPredicate(isTractographyForest); m_Controls->m_FaImageBox->SetPredicate( mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, dimensionPredicate) ); m_Controls->m_FaImageBox->SetZeroEntryText("--"); m_Controls->m_SeedImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_SeedImageBox->SetZeroEntryText("--"); m_Controls->m_MaskImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_MaskImageBox->SetZeroEntryText("--"); m_Controls->m_StopImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_StopImageBox->SetZeroEntryText("--"); m_Controls->m_TargetImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_TargetImageBox->SetZeroEntryText("--"); m_Controls->m_PriorImageBox->SetPredicate( isPeakImagePredicate ); m_Controls->m_PriorImageBox->SetZeroEntryText("--"); m_Controls->m_ExclusionImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_ExclusionImageBox->SetZeroEntryText("--"); connect( m_TrackingTimer, SIGNAL(timeout()), this, SLOT(TimerUpdate()) ); connect( m_Controls->commandLinkButton_2, SIGNAL(clicked()), this, SLOT(StopTractography()) ); connect( m_Controls->commandLinkButton, SIGNAL(clicked()), this, SLOT(DoFiberTracking()) ); connect( m_Controls->m_InteractiveBox, SIGNAL(stateChanged(int)), this, SLOT(ToggleInteractive()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()) ); connect( m_Controls->m_FaImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(DeleteTrackingHandler()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(DeleteTrackingHandler()) ); connect( m_Controls->m_OutputProbMap, SIGNAL(stateChanged(int)), this, SLOT(OutputStyleSwitched()) ); connect( m_Controls->m_SeedImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StopImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_TargetImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_PriorImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ExclusionImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MaskImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FaImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ForestBox, SIGNAL(currentIndexChanged(int)), this, SLOT(ForestSwitched()) ); connect( m_Controls->m_ForestBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_SeedsPerVoxelBox, SIGNAL(valueChanged(int)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_NumFibersBox, SIGNAL(valueChanged(int)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_ScalarThresholdBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_OdfCutoffBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_StepSizeBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_SamplingDistanceBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_AngularThresholdBox, SIGNAL(valueChanged(int)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_MinTractLengthBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_fBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_gBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_NumSamplesBox, SIGNAL(valueChanged(int)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_SeedRadiusBox, SIGNAL(valueChanged(double)), this, SLOT(InteractiveSeedChanged()) ); - connect( m_Controls->m_NumSeedsBox, SIGNAL(valueChanged(int)), this, SLOT(InteractiveSeedChanged()) ); + connect( m_Controls->m_SeedsPerVoxelBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_NumFibersBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_ScalarThresholdBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_OdfCutoffBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_StepSizeBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_SamplingDistanceBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_AngularThresholdBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_MinTractLengthBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_fBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_gBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_NumSamplesBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_SeedRadiusBox, SIGNAL(editingFinished()), this, SLOT(InteractiveSeedChanged()) ); + connect( m_Controls->m_NumSeedsBox, SIGNAL(editingFinished()), this, SLOT(InteractiveSeedChanged()) ); connect( m_Controls->m_OutputProbMap, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SharpenOdfsBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_InterpolationBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MaskInterpolationBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipXBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipYBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipZBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FrontalSamplesBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StopVotesBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_LoopCheckBox, SIGNAL(valueChanged(int)), this, SLOT(OnParameterChanged()) ); - connect( m_Controls->m_TrialsPerSeedBox, SIGNAL(valueChanged(int)), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_LoopCheckBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); + connect( m_Controls->m_TrialsPerSeedBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_EpConstraintsBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); + m_Controls->m_SeedsPerVoxelBox->editingFinished(); + m_Controls->m_NumFibersBox->editingFinished(); + m_Controls->m_ScalarThresholdBox->editingFinished(); + m_Controls->m_OdfCutoffBox->editingFinished(); + m_Controls->m_StepSizeBox->editingFinished(); + m_Controls->m_SamplingDistanceBox->editingFinished(); + m_Controls->m_AngularThresholdBox->editingFinished(); + m_Controls->m_MinTractLengthBox->editingFinished(); + m_Controls->m_fBox->editingFinished(); + m_Controls->m_gBox->editingFinished(); + m_Controls->m_NumSamplesBox->editingFinished(); + m_Controls->m_SeedRadiusBox->editingFinished(); + m_Controls->m_NumSeedsBox->editingFinished(); + m_Controls->m_LoopCheckBox->editingFinished(); + m_Controls->m_TrialsPerSeedBox->editingFinished(); + StartStopTrackingGui(false); } UpdateGui(); } void QmitkStreamlineTrackingView::StopTractography() { if (m_Tracker.IsNull()) return; m_Tracker->SetStopTracking(true); } void QmitkStreamlineTrackingView::TimerUpdate() { if (m_Tracker.IsNull()) return; QString status_text(m_Tracker->GetStatusText().c_str()); m_Controls->m_StatusTextBox->setText(status_text); } void QmitkStreamlineTrackingView::BeforeThread() { m_TrackingTimer->start(1000); } void QmitkStreamlineTrackingView::AfterThread() { m_TrackingTimer->stop(); if (!m_Tracker->GetUseOutputProbabilityMap()) { vtkSmartPointer fiberBundle = m_Tracker->GetFiberPolyData(); if (!m_Controls->m_InteractiveBox->isChecked() && fiberBundle->GetNumberOfLines() == 0) { QMessageBox warnBox; warnBox.setWindowTitle("Warning"); warnBox.setText("No fiberbundle was generated!"); warnBox.setDetailedText("No fibers were generated using the chosen parameters. Typical reasons are:\n\n- Cutoff too high. Some images feature very low FA/GFA/peak size. Try to lower this parameter.\n- Angular threshold too strict. Try to increase this parameter.\n- A small step sizes also means many steps to go wrong. Especially in the case of probabilistic tractography. Try to adjust the angular threshold."); warnBox.setIcon(QMessageBox::Warning); warnBox.exec(); if (m_InteractivePointSetNode.IsNotNull()) m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); StartStopTrackingGui(false); if (m_DeleteTrackingHandler) DeleteTrackingHandler(); UpdateGui(); return; } mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(fiberBundle); fib->SetReferenceGeometry(dynamic_cast(m_ParentNode->GetData())->GetGeometry()); if (m_Controls->m_ResampleFibersBox->isChecked() && fiberBundle->GetNumberOfLines()>0) fib->Compress(m_Controls->m_FiberErrorBox->value()); fib->ColorFibersByOrientation(); m_Tracker->SetDicomProperties(fib); if (m_Controls->m_InteractiveBox->isChecked()) { if (m_InteractiveNode.IsNull()) { m_InteractiveNode = mitk::DataNode::New(); QString name("Interactive"); m_InteractiveNode->SetName(name.toStdString()); GetDataStorage()->Add(m_InteractiveNode); } m_InteractiveNode->SetData(fib); m_InteractiveNode->SetFloatProperty("Fiber2DSliceThickness", m_Tracker->GetMinVoxelSize()/2); if (auto renderWindowPart = this->GetRenderWindowPart()) renderWindowPart->RequestUpdate(); } else { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(fib); QString name("FiberBundle_"); name += m_ParentNode->GetName().c_str(); name += "_Streamline"; node->SetName(name.toStdString()); node->SetFloatProperty("Fiber2DSliceThickness", m_Tracker->GetMinVoxelSize()/2); GetDataStorage()->Add(node, m_ParentNode); } } else { TrackerType::ItkDoubleImgType::Pointer outImg = m_Tracker->GetOutputProbabilityMap(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); if (m_Controls->m_InteractiveBox->isChecked()) { if (m_InteractiveNode.IsNull()) { m_InteractiveNode = mitk::DataNode::New(); QString name("Interactive"); m_InteractiveNode->SetName(name.toStdString()); GetDataStorage()->Add(m_InteractiveNode); } m_InteractiveNode->SetData(img); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::JET_TRANSPARENT); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable(lut); m_InteractiveNode->SetProperty("LookupTable", lut_prop); m_InteractiveNode->SetProperty("opacity", mitk::FloatProperty::New(0.5)); m_InteractiveNode->SetFloatProperty("Fiber2DSliceThickness", m_Tracker->GetMinVoxelSize()/2); if (auto renderWindowPart = this->GetRenderWindowPart()) renderWindowPart->RequestUpdate(); } else { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); QString name("ProbabilityMap_"); name += m_ParentNode->GetName().c_str(); node->SetName(name.toStdString()); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::JET_TRANSPARENT); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable(lut); node->SetProperty("LookupTable", lut_prop); node->SetProperty("opacity", mitk::FloatProperty::New(0.5)); GetDataStorage()->Add(node, m_ParentNode); } } if (m_InteractivePointSetNode.IsNotNull()) m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); StartStopTrackingGui(false); if (m_DeleteTrackingHandler) DeleteTrackingHandler(); UpdateGui(); } void QmitkStreamlineTrackingView::InteractiveSeedChanged(bool posChanged) { if (m_ThreadIsRunning || !m_Visible) return; - if (!posChanged && (!m_Controls->m_InteractiveBox->isChecked() || !m_Controls->m_ParamUpdateBox->isChecked())) + if (!posChanged && (!m_Controls->m_InteractiveBox->isChecked() || !m_Controls->m_ParamUpdateBox->isChecked()) ) + return; + if(!CheckAndStoreLastParams(sender()) && !posChanged) return; std::srand(std::time(0)); m_SeedPoints.clear(); itk::Point world_pos = this->GetRenderWindowPart()->GetSelectedPosition(); m_SeedPoints.push_back(world_pos); float radius = m_Controls->m_SeedRadiusBox->value(); int num = m_Controls->m_NumSeedsBox->value(); mitk::PointSet::Pointer pointset = mitk::PointSet::New(); pointset->InsertPoint(0, world_pos); m_InteractivePointSetNode->SetProperty("pointsize", mitk::FloatProperty::New(radius*2)); m_InteractivePointSetNode->SetProperty("point 2D size", mitk::FloatProperty::New(radius*2)); m_InteractivePointSetNode->SetData(pointset); for (int i=1; i p; p[0] = rand()%1000-500; p[1] = rand()%1000-500; p[2] = rand()%1000-500; p.Normalize(); p *= radius; m_SeedPoints.push_back(world_pos+p); } m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,0,0)); DoFiberTracking(); } +bool QmitkStreamlineTrackingView::CheckAndStoreLastParams(QObject* obj) +{ + if (obj!=nullptr) + { + std::string new_val = ""; + if(qobject_cast(obj)!=nullptr) + new_val = boost::lexical_cast(qobject_cast(obj)->value()); + else if (qobject_cast(obj)!=nullptr) + new_val = boost::lexical_cast(qobject_cast(obj)->value()); + + if (m_LastTractoParams.find(obj->objectName())==m_LastTractoParams.end()) + { + m_LastTractoParams[obj->objectName()] = new_val; + return false; + } + else if (m_LastTractoParams.at(obj->objectName()) != new_val) + { + m_LastTractoParams[obj->objectName()] = new_val; + return true; + } + else if (m_LastTractoParams.at(obj->objectName()) == new_val) + return false; + } + return true; +} + void QmitkStreamlineTrackingView::OnParameterChanged() { + if(!CheckAndStoreLastParams(sender())) + return; + UpdateGui(); if (m_Controls->m_InteractiveBox->isChecked() && m_Controls->m_ParamUpdateBox->isChecked()) DoFiberTracking(); } void QmitkStreamlineTrackingView::ToggleInteractive() { UpdateGui(); m_Controls->m_SeedsPerVoxelBox->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->m_SeedsPerVoxelLabel->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->m_SeedImageBox->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->label_6->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); if ( m_Controls->m_InteractiveBox->isChecked() ) { if (m_FirstInteractiveRun) { QMessageBox::information(nullptr, "Information", "Place and move a spherical seed region anywhere in the image by left-clicking and dragging. If the seed region is colored red, tracking is in progress. If the seed region is colored white, tracking is finished.\nPlacing the seed region for the first time in a newly selected dataset might cause a short delay, since the tracker needs to be initialized."); m_FirstInteractiveRun = false; } QApplication::setOverrideCursor(Qt::PointingHandCursor); QApplication::processEvents(); m_InteractivePointSetNode = mitk::DataNode::New(); m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); m_InteractivePointSetNode->SetName("InteractiveSeedRegion"); mitk::PointSetShapeProperty::Pointer shape_prop = mitk::PointSetShapeProperty::New(); shape_prop->SetValue(mitk::PointSetShapeProperty::PointSetShape::CIRCLE); m_InteractivePointSetNode->SetProperty("Pointset.2D.shape", shape_prop); GetDataStorage()->Add(m_InteractivePointSetNode); m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } else { QApplication::restoreOverrideCursor(); QApplication::processEvents(); m_InteractiveNode = nullptr; m_InteractivePointSetNode = nullptr; m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); disconnect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } } void QmitkStreamlineTrackingView::Activated() { } void QmitkStreamlineTrackingView::Deactivated() { } void QmitkStreamlineTrackingView::Visible() { m_Visible = true; } void QmitkStreamlineTrackingView::Hidden() { m_Visible = false; m_Controls->m_InteractiveBox->setChecked(false); ToggleInteractive(); } void QmitkStreamlineTrackingView::OnSliceChanged() { InteractiveSeedChanged(true); } void QmitkStreamlineTrackingView::SetFocus() { } void QmitkStreamlineTrackingView::DeleteTrackingHandler() { if (!m_ThreadIsRunning && m_TrackingHandler != nullptr) { delete m_TrackingHandler; m_TrackingHandler = nullptr; m_DeleteTrackingHandler = false; m_LastPrior = ""; if (m_TrackingPriorHandler != nullptr) delete m_TrackingPriorHandler; } else if (m_ThreadIsRunning) { m_DeleteTrackingHandler = true; } } void QmitkStreamlineTrackingView::ForestSwitched() { DeleteTrackingHandler(); } void QmitkStreamlineTrackingView::OutputStyleSwitched() { if (m_InteractiveNode.IsNotNull()) GetDataStorage()->Remove(m_InteractiveNode); m_InteractiveNode = nullptr; } void QmitkStreamlineTrackingView::OnSelectionChanged( berry::IWorkbenchPart::Pointer , const QList& nodes ) { std::vector< mitk::DataNode::Pointer > last_nodes = m_InputImageNodes; m_InputImageNodes.clear(); m_InputImages.clear(); m_AdditionalInputImages.clear(); bool retrack = false; for( auto node : nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { if( dynamic_cast(node->GetData()) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else if ( dynamic_cast(node->GetData()) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(node->GetData())) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else { mitk::Image* img = dynamic_cast(node->GetData()); if (img!=nullptr) { int dim = img->GetDimension(); unsigned int* dimensions = img->GetDimensions(); if (dim==4 && dimensions[3]%3==0) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else if (dim==3) { m_AdditionalInputImages.push_back(dynamic_cast(node->GetData())); } } } } } // sometimes the OnSelectionChanged event is sent twice and actually no selection has changed for the first event. We need to catch that. if (last_nodes.size() == m_InputImageNodes.size()) { bool same_nodes = true; for (unsigned int i=0; im_TensorImageLabel->setText("select in data-manager"); m_Controls->m_fBox->setEnabled(false); m_Controls->m_fLabel->setEnabled(false); m_Controls->m_gBox->setEnabled(false); m_Controls->m_gLabel->setEnabled(false); m_Controls->m_FaImageBox->setEnabled(true); m_Controls->mFaImageLabel->setEnabled(true); m_Controls->m_OdfCutoffBox->setEnabled(false); m_Controls->m_OdfCutoffLabel->setEnabled(false); m_Controls->m_SharpenOdfsBox->setEnabled(false); m_Controls->m_ForestBox->setVisible(false); m_Controls->m_ForestLabel->setVisible(false); m_Controls->commandLinkButton->setEnabled(false); m_Controls->m_TrialsPerSeedBox->setEnabled(false); m_Controls->m_TrialsPerSeedLabel->setEnabled(false); m_Controls->m_TargetImageBox->setVisible(false); m_Controls->m_TargetImageLabel->setVisible(false); if (m_Controls->m_InteractiveBox->isChecked()) { m_Controls->m_InteractiveSeedingFrame->setVisible(true); m_Controls->m_StaticSeedingFrame->setVisible(false); m_Controls->commandLinkButton_2->setVisible(false); m_Controls->commandLinkButton->setVisible(false); } else { m_Controls->m_InteractiveSeedingFrame->setVisible(false); m_Controls->m_StaticSeedingFrame->setVisible(true); m_Controls->commandLinkButton_2->setVisible(m_ThreadIsRunning); m_Controls->commandLinkButton->setVisible(!m_ThreadIsRunning); } if (m_Controls->m_EpConstraintsBox->currentIndex()>0) { m_Controls->m_TargetImageBox->setVisible(true); m_Controls->m_TargetImageLabel->setVisible(true); } // trials per seed are only important for probabilistic tractography if (m_Controls->m_ModeBox->currentIndex()==1) { m_Controls->m_TrialsPerSeedBox->setEnabled(true); m_Controls->m_TrialsPerSeedLabel->setEnabled(true); } if(!m_InputImageNodes.empty()) { if (m_InputImageNodes.size()>1) m_Controls->m_TensorImageLabel->setText( ( std::to_string(m_InputImageNodes.size()) + " images selected").c_str() ); else m_Controls->m_TensorImageLabel->setText(m_InputImageNodes.at(0)->GetName().c_str()); m_Controls->commandLinkButton->setEnabled(!m_Controls->m_InteractiveBox->isChecked() && !m_ThreadIsRunning); m_Controls->m_ScalarThresholdBox->setEnabled(true); m_Controls->m_FaThresholdLabel->setEnabled(true); if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { m_Controls->m_fBox->setEnabled(true); m_Controls->m_fLabel->setEnabled(true); m_Controls->m_gBox->setEnabled(true); m_Controls->m_gLabel->setEnabled(true); } else if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { m_Controls->m_OdfCutoffBox->setEnabled(true); m_Controls->m_OdfCutoffLabel->setEnabled(true); m_Controls->m_SharpenOdfsBox->setEnabled(true); } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_InputImageNodes.at(0)->GetData())) ) { m_Controls->m_ForestBox->setVisible(true); m_Controls->m_ForestLabel->setVisible(true); m_Controls->m_ScalarThresholdBox->setEnabled(false); m_Controls->m_FaThresholdLabel->setEnabled(false); } } } void QmitkStreamlineTrackingView::StartStopTrackingGui(bool start) { m_ThreadIsRunning = start; if (!m_Controls->m_InteractiveBox->isChecked()) { m_Controls->commandLinkButton_2->setVisible(start); m_Controls->commandLinkButton->setVisible(!start); m_Controls->m_InteractiveBox->setEnabled(!start); m_Controls->m_StatusTextBox->setVisible(start); } } void QmitkStreamlineTrackingView::DoFiberTracking() { if (m_ThreadIsRunning || m_InputImages.empty() || !m_Visible) return; if (m_Controls->m_InteractiveBox->isChecked() && m_SeedPoints.empty()) return; StartStopTrackingGui(true); m_Tracker = TrackerType::New(); if( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { if (m_Controls->m_ModeBox->currentIndex()==1) { if (m_InputImages.size()>1) { QMessageBox::information(nullptr, "Information", "Probabilistic tensor tractography is only implemented for single-tensor mode!"); StartStopTrackingGui(false); return; } if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerOdf(); mitk::TensorImage::ItkTensorImageType::Pointer itkImg = mitk::TensorImage::ItkTensorImageType::New(); mitk::CastToItkImage(m_InputImages.at(0), itkImg); typedef itk::TensorImageToOdfImageFilter< float, float > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkImg ); filter->Update(); dynamic_cast(m_TrackingHandler)->SetOdfImage(filter->GetOutput()); if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetGfaImage(itkImg); } } dynamic_cast(m_TrackingHandler)->SetGfaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(m_TrackingHandler)->SetOdfThreshold(0); dynamic_cast(m_TrackingHandler)->SetSharpenOdfs(true); dynamic_cast(m_TrackingHandler)->SetIsOdfFromTensor(true); } else { if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerTensor(); for (int i=0; i<(int)m_InputImages.size(); i++) { typedef mitk::ImageToItk< mitk::TrackingHandlerTensor::ItkTensorImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(m_InputImages.at(i)); caster->Update(); mitk::TrackingHandlerTensor::ItkTensorImageType::ConstPointer itkImg = caster->GetOutput(); dynamic_cast(m_TrackingHandler)->AddTensorImage(itkImg); } if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetFaImage(itkImg); } } dynamic_cast(m_TrackingHandler)->SetFaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(m_TrackingHandler)->SetF((float)m_Controls->m_fBox->value()); dynamic_cast(m_TrackingHandler)->SetG((float)m_Controls->m_gBox->value()); } } else if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerOdf(); mitk::TrackingHandlerOdf::ItkOdfImageType::Pointer itkImg = mitk::TrackingHandlerOdf::ItkOdfImageType::New(); mitk::CastToItkImage(m_InputImages.at(0), itkImg); dynamic_cast(m_TrackingHandler)->SetOdfImage(itkImg); if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetGfaImage(itkImg); } } dynamic_cast(m_TrackingHandler)->SetGfaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(m_TrackingHandler)->SetOdfThreshold(m_Controls->m_OdfCutoffBox->value()); dynamic_cast(m_TrackingHandler)->SetSharpenOdfs(m_Controls->m_SharpenOdfsBox->isChecked()); } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_InputImageNodes.at(0)->GetData())) ) { if ( m_Controls->m_ForestBox->GetSelectedNode().IsNull() ) { QMessageBox::information(nullptr, "Information", "Not random forest for machine learning based tractography (raw dMRI tractography) selected. Did you accidentally select the raw diffusion-weighted image in the datamanager?"); StartStopTrackingGui(false); return; } if (m_TrackingHandler==nullptr) { mitk::TractographyForest::Pointer forest = dynamic_cast(m_Controls->m_ForestBox->GetSelectedNode()->GetData()); mitk::Image::Pointer dwi = dynamic_cast(m_InputImageNodes.at(0)->GetData()); std::vector< std::vector< ItkFloatImageType::Pointer > > additionalFeatureImages; additionalFeatureImages.push_back(std::vector< ItkFloatImageType::Pointer >()); for (auto img : m_AdditionalInputImages) { ItkFloatImageType::Pointer itkimg = ItkFloatImageType::New(); mitk::CastToItkImage(img, itkimg); additionalFeatureImages.at(0).push_back(itkimg); } bool forest_valid = false; if (forest->GetNumFeatures()>=100) { int num_previous_directions = (forest->GetNumFeatures() - (100 + additionalFeatureImages.at(0).size()))/3; m_TrackingHandler = new mitk::TrackingHandlerRandomForest<6, 100>(); dynamic_cast*>(m_TrackingHandler)->AddDwi(dwi); dynamic_cast*>(m_TrackingHandler)->SetAdditionalFeatureImages(additionalFeatureImages); dynamic_cast*>(m_TrackingHandler)->SetForest(forest); dynamic_cast*>(m_TrackingHandler)->SetNumPreviousDirections(num_previous_directions); forest_valid = dynamic_cast*>(m_TrackingHandler)->IsForestValid(); } else { int num_previous_directions = (forest->GetNumFeatures() - (28 + additionalFeatureImages.at(0).size()))/3; m_TrackingHandler = new mitk::TrackingHandlerRandomForest<6, 28>(); dynamic_cast*>(m_TrackingHandler)->AddDwi(dwi); dynamic_cast*>(m_TrackingHandler)->SetAdditionalFeatureImages(additionalFeatureImages); dynamic_cast*>(m_TrackingHandler)->SetForest(forest); dynamic_cast*>(m_TrackingHandler)->SetNumPreviousDirections(num_previous_directions); forest_valid = dynamic_cast*>(m_TrackingHandler)->IsForestValid(); } if (!forest_valid) { QMessageBox::information(nullptr, "Information", "Random forest is invalid. The forest signatue does not match the parameters of TrackingHandlerRandomForest."); StartStopTrackingGui(false); return; } } } else { if (m_Controls->m_ModeBox->currentIndex()==1) { QMessageBox::information(nullptr, "Information", "Probabilstic tractography is not implemented for peak images."); StartStopTrackingGui(false); return; } try { if (m_TrackingHandler==nullptr) { typedef mitk::ImageToItk< mitk::TrackingHandlerPeaks::PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(m_InputImages.at(0)); caster->SetCopyMemFlag(true); caster->Update(); mitk::TrackingHandlerPeaks::PeakImgType::Pointer itkImg = caster->GetOutput(); m_TrackingHandler = new mitk::TrackingHandlerPeaks(); dynamic_cast(m_TrackingHandler)->SetPeakImage(itkImg); } dynamic_cast(m_TrackingHandler)->SetPeakThreshold(m_Controls->m_ScalarThresholdBox->value()); } catch(...) { QMessageBox::information(nullptr, "Error", "Peak tracker could not be initialized. Is your input image in the correct format (4D float image, peaks in the 4th dimension)?"); StartStopTrackingGui(false); return; } } m_TrackingHandler->SetFlipX(m_Controls->m_FlipXBox->isChecked()); m_TrackingHandler->SetFlipY(m_Controls->m_FlipYBox->isChecked()); m_TrackingHandler->SetFlipZ(m_Controls->m_FlipZBox->isChecked()); m_TrackingHandler->SetInterpolate(m_Controls->m_InterpolationBox->isChecked()); switch (m_Controls->m_ModeBox->currentIndex()) { case 0: m_TrackingHandler->SetMode(mitk::TrackingDataHandler::MODE::DETERMINISTIC); break; case 1: m_TrackingHandler->SetMode(mitk::TrackingDataHandler::MODE::PROBABILISTIC); break; default: m_TrackingHandler->SetMode(mitk::TrackingDataHandler::MODE::DETERMINISTIC); } if (m_Controls->m_InteractiveBox->isChecked()) { m_Tracker->SetSeedPoints(m_SeedPoints); } else if (m_Controls->m_SeedImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_SeedImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetSeedImage(mask); } if (m_Controls->m_MaskImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_MaskImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetMaskImage(mask); } if (m_Controls->m_StopImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_StopImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetStoppingRegions(mask); } if (m_Controls->m_TargetImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_TargetImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetTargetRegions(mask); } if (m_Controls->m_PriorImageBox->GetSelectedNode().IsNotNull()) { if (m_LastPrior!=m_Controls->m_PriorImageBox->GetSelectedNode()->GetUID() || m_TrackingPriorHandler==nullptr) { typedef mitk::ImageToItk< mitk::TrackingHandlerPeaks::PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(dynamic_cast(m_Controls->m_PriorImageBox->GetSelectedNode()->GetData())); caster->SetCopyMemFlag(true); caster->Update(); mitk::TrackingHandlerPeaks::PeakImgType::Pointer itkImg = caster->GetOutput(); m_TrackingPriorHandler = new mitk::TrackingHandlerPeaks(); dynamic_cast(m_TrackingPriorHandler)->SetPeakImage(itkImg); dynamic_cast(m_TrackingPriorHandler)->SetPeakThreshold(0.0); m_LastPrior = m_Controls->m_PriorImageBox->GetSelectedNode()->GetUID(); } m_TrackingPriorHandler->SetInterpolate(m_Controls->m_InterpolationBox->isChecked()); m_TrackingPriorHandler->SetMode(mitk::TrackingDataHandler::MODE::DETERMINISTIC); m_Tracker->SetTrackingPriorHandler(m_TrackingPriorHandler); m_Tracker->SetTrackingPriorWeight(m_Controls->m_PriorWeightBox->value()); m_Tracker->SetTrackingPriorAsMask(m_Controls->m_PriorAsMaskBox->isChecked()); m_Tracker->SetIntroduceDirectionsFromPrior(m_Controls->m_NewDirectionsFromPriorBox->isChecked()); } else if (m_Controls->m_PriorImageBox->GetSelectedNode().IsNull()) m_Tracker->SetTrackingPriorHandler(nullptr); if (m_Controls->m_ExclusionImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_ExclusionImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetExclusionRegions(mask); } // Endpoint constraints switch (m_Controls->m_EpConstraintsBox->currentIndex()) { case 0: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::NONE); m_Tracker->SetTargetRegions(nullptr); break; case 1: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_TARGET); break; case 2: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_TARGET_LABELDIFF); break; case 3: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_SEED_AND_TARGET); break; case 4: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::MIN_ONE_EP_IN_TARGET); break; case 5: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::ONE_EP_IN_TARGET); break; case 6: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::NO_EP_IN_TARGET); break; } if (m_Tracker->GetEndpointConstraint()!=itk::StreamlineTrackingFilter::EndpointConstraints::NONE && m_Controls->m_TargetImageBox->GetSelectedNode().IsNull()) { QMessageBox::information(nullptr, "Error", "Endpoint constraints are used but no target image is set!"); StartStopTrackingGui(false); return; } else if (m_Tracker->GetEndpointConstraint()==itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_SEED_AND_TARGET && (m_Controls->m_SeedImageBox->GetSelectedNode().IsNull()|| m_Controls->m_TargetImageBox->GetSelectedNode().IsNull()) ) { QMessageBox::information(nullptr, "Error", "Endpoint constraint EPS_IN_SEED_AND_TARGET is used but no target or no seed image is set!"); StartStopTrackingGui(false); return; } m_Tracker->SetInterpolateMasks(m_Controls->m_MaskInterpolationBox->isChecked()); m_Tracker->SetVerbose(!m_Controls->m_InteractiveBox->isChecked()); m_Tracker->SetSeedsPerVoxel(m_Controls->m_SeedsPerVoxelBox->value()); m_Tracker->SetStepSize(m_Controls->m_StepSizeBox->value()); m_Tracker->SetSamplingDistance(m_Controls->m_SamplingDistanceBox->value()); m_Tracker->SetUseStopVotes(m_Controls->m_StopVotesBox->isChecked()); m_Tracker->SetOnlyForwardSamples(m_Controls->m_FrontalSamplesBox->isChecked()); m_Tracker->SetTrialsPerSeed(m_Controls->m_TrialsPerSeedBox->value()); m_Tracker->SetMaxNumTracts(m_Controls->m_NumFibersBox->value()); m_Tracker->SetNumberOfSamples(m_Controls->m_NumSamplesBox->value()); m_Tracker->SetTrackingHandler(m_TrackingHandler); m_Tracker->SetLoopCheck(m_Controls->m_LoopCheckBox->value()); m_Tracker->SetAngularThreshold(m_Controls->m_AngularThresholdBox->value()); m_Tracker->SetMinTractLength(m_Controls->m_MinTractLengthBox->value()); m_Tracker->SetUseOutputProbabilityMap(m_Controls->m_OutputProbMap->isChecked()); m_ParentNode = m_InputImageNodes.at(0); m_TrackingThread.start(QThread::LowestPriority); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.h index d5d0d6ee99..0a3a3e1838 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.h @@ -1,153 +1,155 @@ /*=================================================================== 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 QmitkStreamlineTrackingView_h #define QmitkStreamlineTrackingView_h #include #include "ui_QmitkStreamlineTrackingViewControls.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class QmitkStreamlineTrackingView; class QmitkStreamlineTrackingWorker : public QObject { Q_OBJECT public: QmitkStreamlineTrackingWorker(QmitkStreamlineTrackingView* view); public slots: void run(); private: QmitkStreamlineTrackingView* m_View; }; /*! \brief View for tensor based deterministic streamline fiber tracking. */ class QmitkStreamlineTrackingView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { // 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; typedef itk::Image< unsigned int, 3 > ItkUintImgType; typedef itk::Image< unsigned char, 3 > ItkUCharImageType; typedef itk::Image< float, 3 > ItkFloatImageType; typedef itk::StreamlineTrackingFilter TrackerType; QmitkStreamlineTrackingView(); virtual ~QmitkStreamlineTrackingView(); virtual void CreateQtPartControl(QWidget *parent) override; /// /// Sets the focus to an internal widget. /// virtual void SetFocus() override; TrackerType::Pointer m_Tracker; QmitkStreamlineTrackingWorker m_TrackingWorker; QThread m_TrackingThread; virtual void Activated() override; virtual void Deactivated() override; virtual void Visible() override; virtual void Hidden() override; protected slots: void DoFiberTracking(); ///< start fiber tracking void UpdateGui(); void ToggleInteractive(); void DeleteTrackingHandler(); void OnParameterChanged(); void InteractiveSeedChanged(bool posChanged=false); void ForestSwitched(); void OutputStyleSwitched(); void AfterThread(); ///< update gui etc. after tracking has finished void BeforeThread(); ///< start timer etc. void TimerUpdate(); void StopTractography(); void OnSliceChanged(); protected: /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; Ui::QmitkStreamlineTrackingViewControls* m_Controls; protected slots: private: + bool CheckAndStoreLastParams(QObject* obj); void StartStopTrackingGui(bool start); std::vector< itk::Point > m_SeedPoints; mitk::DataNode::Pointer m_ParentNode; mitk::DataNode::Pointer m_InteractiveNode; mitk::DataNode::Pointer m_InteractivePointSetNode; std::vector< mitk::DataNode::Pointer > m_InputImageNodes; ///< input image nodes std::vector< mitk::Image::ConstPointer > m_InputImages; ///< input images std::vector< mitk::Image::ConstPointer > m_AdditionalInputImages; bool m_FirstTensorProbRun; bool m_FirstInteractiveRun; mitk::TrackingDataHandler* m_TrackingHandler; bool m_ThreadIsRunning; QTimer* m_TrackingTimer; bool m_DeleteTrackingHandler; QmitkSliceNavigationListener m_SliceChangeListener; bool m_Visible; mitk::Identifiable::UIDType m_LastPrior; mitk::TrackingDataHandler* m_TrackingPriorHandler; + std::map< QString, std::string > m_LastTractoParams; }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp index 7c54d0dbbf..c423c9740b 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp @@ -1,1293 +1,1333 @@ /*=================================================================== 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 "QmitkControlVisualizationPropertiesView.h" #include "mitkNodePredicateDataType.h" #include "mitkDataNodeObject.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include "mitkResliceMethodProperty.h" #include "mitkRenderingManager.h" #include "mitkImageCast.h" #include "mitkShImage.h" #include "mitkPlanarFigure.h" #include "mitkFiberBundle.h" #include "QmitkDataStorageComboBox.h" #include "mitkPlanarFigureInteractor.h" #include #include #include #include #include #include "usModuleRegistry.h" #include #include #include "mitkPlaneGeometry.h" #include #include #include #include "berryIWorkbenchWindow.h" #include "berryIWorkbenchPage.h" #include "berryISelectionService.h" #include "berryConstants.h" #include "berryPlatformUI.h" #include "itkRGBAPixel.h" #include #include "qwidgetaction.h" #include "qcolordialog.h" #include #include - +#include #include #define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) const std::string QmitkControlVisualizationPropertiesView::VIEW_ID = "org.mitk.views.controlvisualizationpropertiesview"; using namespace berry; QmitkControlVisualizationPropertiesView::QmitkControlVisualizationPropertiesView() : QmitkAbstractView(), m_Controls(nullptr), m_CurrentSelection(0), m_IconTexOFF(new QIcon(":/QmitkDiffusionImaging/texIntOFFIcon.png")), m_IconTexON(new QIcon(":/QmitkDiffusionImaging/texIntONIcon.png")), m_IconGlyOFF_T(new QIcon(":/QmitkDiffusionImaging/glyphsoff_T.png")), m_IconGlyON_T(new QIcon(":/QmitkDiffusionImaging/glyphson_T.png")), m_IconGlyOFF_C(new QIcon(":/QmitkDiffusionImaging/glyphsoff_C.png")), m_IconGlyON_C(new QIcon(":/QmitkDiffusionImaging/glyphson_C.png")), m_IconGlyOFF_S(new QIcon(":/QmitkDiffusionImaging/glyphsoff_S.png")), m_IconGlyON_S(new QIcon(":/QmitkDiffusionImaging/glyphson_S.png")), m_GlyIsOn_T(false), m_GlyIsOn_C(false), m_GlyIsOn_S(false), m_CurrentPickingNode(0), m_ColorPropertyObserverTag(0), m_OpacityPropertyObserverTag(0) { currentThickSlicesMode = 1; m_MyMenu = nullptr; int numThread = itk::MultiThreader::GetGlobalMaximumNumberOfThreads(); if (numThread > 12) numThread = 12; itk::MultiThreader::SetGlobalDefaultNumberOfThreads(numThread); } QmitkControlVisualizationPropertiesView::~QmitkControlVisualizationPropertiesView() { } void QmitkControlVisualizationPropertiesView::OnThickSlicesModeSelected( QAction* action ) { currentThickSlicesMode = action->data().toInt(); switch( currentThickSlicesMode ) { case 0: // toInt() returns 0 'otherwise'. return; // dummy code/todo: implement stuff. case 1: this->m_Controls->m_TSMenu->setText("MIP"); break; case 2: this->m_Controls->m_TSMenu->setText("SUM"); break; case 3: this->m_Controls->m_TSMenu->setText("WEIGH"); break; default: return; // dummy code/todo: implement stuff. } if (auto renderWindowPart = this->GetRenderWindowPart(OPEN)) { /// TODO There is no way to access the individual crosshair planes through the render window part API. /// There could be a new 'mitk::DataNode* mitk::ILinkedRenderWindowPart::GetSlicingPlane(const std::string& name) const' /// function for this purpose. For the time being, I comment out the lines below, but they are valid /// and they have to be re-enabled after the crosshair planes can be accessed again. // mitk::DataNode* n; // n = renderWindowPart->GetSlicingPlane("axial"); // if (n) { n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); } // n = renderWindowPart->GetSlicingPlane("sagittal"); // if (n) { n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); } // n = renderWindowPart->GetSlicingPlane("coronal"); // if (n) { n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); } mitk::BaseRenderer::Pointer renderer; renderer = renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer(); if (renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer(); if (renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer(); if (renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer->GetRenderingManager()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::OnTSNumChanged( int num ) { if (auto renderWindowPart = this->GetRenderWindowPart(OPEN)) { /// TODO There is no way to access the individual crosshair planes through the render window part API. /// There could be a new 'mitk::DataNode* mitk::ILinkedRenderWindowPart::GetSlicingPlane(const std::string& name) const' /// function for this purpose. For the time being, I comment out the lines below, but they are valid /// and they have to be re-enabled after the crosshair planes can be accessed again. // if(num==0) // { // mitk::DataNode* n; // n = renderWindowPart->GetSlicingPlane("axial"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( false ) ); // // n = renderWindowPart->GetSlicingPlane("sagittal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( false ) ); // // n = renderWindowPart->GetSlicingPlane("coronal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( false ) ); // } // else // { // mitk::DataNode* n; // n = renderWindowPart->GetSlicingPlane("axial"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( (num>0) ) ); // // n = renderWindowPart->GetSlicingPlane("sagittal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( (num>0) ) ); // // n = renderWindowPart->GetSlicingPlane("coronal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( (num>0) ) ); // } m_TSLabel->setText(QString::number( num*2 + 1 )); mitk::BaseRenderer::Pointer renderer; renderer = renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = nullptr; renderer = renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = nullptr; renderer = renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer->GetRenderingManager()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); } } void QmitkControlVisualizationPropertiesView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkControlVisualizationPropertiesViewControls; m_Controls->setupUi(parent); this->CreateConnections(); // hide warning (ODFs in rotated planes) m_Controls->m_lblRotatedPlanesWarning->hide(); m_MyMenu = new QMenu(parent); m_Controls->m_TSMenu->setMenu( m_MyMenu ); QIcon iconFiberFade(":/QmitkDiffusionImaging/MapperEfx2D.png"); m_Controls->m_FiberFading2D->setIcon(iconFiberFade); #ifndef DIFFUSION_IMAGING_EXTENDED int size = m_Controls->m_AdditionalScaling->count(); for(int t=0; tm_AdditionalScaling->itemText(t).toStdString() == "Scale by ASR") { m_Controls->m_AdditionalScaling->removeItem(t); } } #endif m_Controls->m_NormalizationFrame->setVisible(false); m_Controls->m_Crosshair->setVisible(false); mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow) { m_SliceChangeListener.RenderWindowPartActivated(renderWindow); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } connect(m_Controls->m_SetColor1, SIGNAL(clicked()), this, SLOT(SetColor())); connect(m_Controls->m_SetColor2, SIGNAL(clicked()), this, SLOT(SetColor())); } } void QmitkControlVisualizationPropertiesView::SetColor() { if(m_SelectedNode) { QColor c = QColorDialog::getColor(); float rgb[3]; rgb[0] = c.redF(); rgb[1] = c.greenF(); rgb[2] = c.blueF(); m_SelectedNode->SetColor(rgb); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::SetFocus() { m_Controls->m_TSMenu->setFocus(); } void QmitkControlVisualizationPropertiesView::SliceRotation(const itk::EventObject&) { // test if plane rotated if( m_GlyIsOn_T || m_GlyIsOn_C || m_GlyIsOn_S ) { if( this->IsPlaneRotated() ) { // show label m_Controls->m_lblRotatedPlanesWarning->show(); } else { //hide label m_Controls->m_lblRotatedPlanesWarning->hide(); } } } void QmitkControlVisualizationPropertiesView::NodeRemoved(const mitk::DataNode* /*node*/) { } #include void QmitkControlVisualizationPropertiesView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_VisibleOdfsON_T), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_T()) ); connect( (QObject*)(m_Controls->m_VisibleOdfsON_S), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_S()) ); connect( (QObject*)(m_Controls->m_VisibleOdfsON_C), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_C()) ); connect( (QObject*)(m_Controls->m_ShowMaxNumber), SIGNAL(editingFinished()), this, SLOT(ShowMaxNumberChanged()) ); connect( (QObject*)(m_Controls->m_NormalizationDropdown), SIGNAL(currentIndexChanged(int)), this, SLOT(NormalizationDropdownChanged(int)) ); connect( (QObject*)(m_Controls->m_ScalingFactor), SIGNAL(valueChanged(double)), this, SLOT(ScalingFactorChanged(double)) ); connect( (QObject*)(m_Controls->m_AdditionalScaling), SIGNAL(currentIndexChanged(int)), this, SLOT(AdditionalScaling(int)) ); connect((QObject*) m_Controls->m_ResetColoring, SIGNAL(clicked()), (QObject*) this, SLOT(ResetColoring())); connect((QObject*) m_Controls->m_ResetColoring2, SIGNAL(clicked()), (QObject*) this, SLOT(ResetColoring())); connect((QObject*) m_Controls->m_FiberFading2D, SIGNAL(clicked()), (QObject*) this, SLOT( Fiber2DfadingEFX() ) ); connect((QObject*) m_Controls->m_FiberThicknessSlider, SIGNAL(sliderReleased()), (QObject*) this, SLOT( FiberSlicingThickness2D() ) ); connect((QObject*) m_Controls->m_FiberThicknessSlider, SIGNAL(valueChanged(int)), (QObject*) this, SLOT( FiberSlicingUpdateLabel(int) )); connect((QObject*) m_Controls->m_Crosshair, SIGNAL(clicked()), (QObject*) this, SLOT(SetInteractor())); connect((QObject*) m_Controls->m_LineWidth, SIGNAL(editingFinished()), (QObject*) this, SLOT(LineWidthChanged())); connect((QObject*) m_Controls->m_TubeWidth, SIGNAL(editingFinished()), (QObject*) this, SLOT(TubeRadiusChanged())); + connect((QObject*) m_Controls->m_RibbonWidth, SIGNAL(editingFinished()), (QObject*) this, SLOT(RibbonWidthChanged())); connect( (QObject*) m_Controls->m_OdfColorBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnColourisationModeChanged() ) ); connect((QObject*) m_Controls->m_Clip0, SIGNAL(toggled(bool)), (QObject*) this, SLOT(Toggle3DClipping(bool))); connect((QObject*) m_Controls->m_Clip1, SIGNAL(toggled(bool)), (QObject*) this, SLOT(Toggle3DClipping(bool))); connect((QObject*) m_Controls->m_Clip2, SIGNAL(toggled(bool)), (QObject*) this, SLOT(Toggle3DClipping(bool))); connect((QObject*) m_Controls->m_Clip3, SIGNAL(toggled(bool)), (QObject*) this, SLOT(Toggle3DClipping(bool))); connect((QObject*) m_Controls->m_FlipClipBox, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(Toggle3DClipping())); + connect((QObject*) m_Controls->m_Enable3dPeaks, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(Toggle3DPeaks())); connect((QObject*) m_Controls->m_FlipPeaksButton, SIGNAL(clicked()), (QObject*) this, SLOT(FlipPeaks())); + + m_Controls->m_BundleControlsFrame->setVisible(false); + m_Controls->m_ImageControlsFrame->setVisible(false); + m_Controls->m_PeakImageFrame->setVisible(false); + m_Controls->m_lblRotatedPlanesWarning->setVisible(false); + m_Controls->m_3DClippingBox->setVisible(false); } } // set diffusion image channel to b0 volume void QmitkControlVisualizationPropertiesView::NodeAdded(const mitk::DataNode *node) { mitk::DataNode* notConst = const_cast(node); bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(node->GetData())) ); if (isDiffusionImage) { mitk::Image::Pointer dimg = dynamic_cast(notConst->GetData()); // if there is no b0 image in the dataset, the GetB0Indices() returns a vector of size 0 // and hence we cannot set the Property directly to .front() int displayChannelPropertyValue = 0; mitk::BValueMapProperty* bmapproperty = static_cast (dimg->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ); mitk::DiffusionPropertyHelper::BValueMapType map = bmapproperty->GetBValueMap(); if( map[0].size() > 0) { displayChannelPropertyValue = map[0].front(); } notConst->SetIntProperty("DisplayChannel", displayChannelPropertyValue ); } } /* OnSelectionChanged is registered to SelectionService, therefore no need to implement SelectionService Listener explicitly */ void QmitkControlVisualizationPropertiesView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { m_Controls->m_BundleControlsFrame->setVisible(false); m_Controls->m_ImageControlsFrame->setVisible(false); m_Controls->m_PeakImageFrame->setVisible(false); + m_Controls->m_3DClippingBox->setVisible(false); + m_Controls->m_FlipClipBox->setVisible(false); + m_Controls->m_Enable3dPeaks->setVisible(false); if (nodes.size()>1) // only do stuff if one node is selected return; m_Controls->m_NumberGlyphsFrame->setVisible(false); m_Controls->m_GlyphFrame->setVisible(false); m_Controls->m_TSMenu->setVisible(false); m_SelectedNode = nullptr; int numOdfImages = 0; for (mitk::DataNode::Pointer node: nodes) { if(node.IsNull()) continue; mitk::BaseData* nodeData = node->GetData(); if(nodeData == nullptr) continue; m_SelectedNode = node; if (dynamic_cast(nodeData)) { m_Controls->m_PeakImageFrame->setVisible(true); if (m_Color.IsNotNull()) m_Color->RemoveObserver(m_ColorPropertyObserverTag); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SetCustomColor ); m_Color = dynamic_cast(node->GetProperty("color", nullptr)); if (m_Color.IsNotNull()) m_ColorPropertyObserverTag = m_Color->AddObserver( itk::ModifiedEvent(), command ); + + int ClippingPlaneId = -1; + m_SelectedNode->GetPropertyValue("3DClippingPlaneId",ClippingPlaneId); + switch(ClippingPlaneId) + { + case 0: + m_Controls->m_Clip0->setChecked(1); + break; + case 1: + m_Controls->m_Clip1->setChecked(1); + break; + case 2: + m_Controls->m_Clip2->setChecked(1); + break; + case 3: + m_Controls->m_Clip3->setChecked(1); + break; + default : + m_Controls->m_Clip0->setChecked(1); + } + + m_Controls->m_Enable3dPeaks->setVisible(true); + m_Controls->m_3DClippingBox->setVisible(true); } else if (dynamic_cast(nodeData)) { - int Fiber3DClippingPlaneId = -1; - m_SelectedNode->GetPropertyValue("Fiber3DClippingPlaneId",Fiber3DClippingPlaneId); - switch(Fiber3DClippingPlaneId) + int ClippingPlaneId = -1; + m_SelectedNode->GetPropertyValue("3DClippingPlaneId",ClippingPlaneId); + switch(ClippingPlaneId) { case 0: m_Controls->m_Clip0->setChecked(1); break; case 1: m_Controls->m_Clip1->setChecked(1); break; case 2: m_Controls->m_Clip2->setChecked(1); break; case 3: m_Controls->m_Clip3->setChecked(1); break; default : m_Controls->m_Clip0->setChecked(1); } // handle fiber property observers if (m_Color.IsNotNull()) m_Color->RemoveObserver(m_ColorPropertyObserverTag); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SetCustomColor ); m_Color = dynamic_cast(node->GetProperty("color", nullptr)); if (m_Color.IsNotNull()) m_ColorPropertyObserverTag = m_Color->AddObserver( itk::ModifiedEvent(), command ); - + m_Controls->m_FlipClipBox->setVisible(true); + m_Controls->m_3DClippingBox->setVisible(true); m_Controls->m_BundleControlsFrame->setVisible(true); if(m_CurrentPickingNode != 0 && node.GetPointer() != m_CurrentPickingNode) { m_Controls->m_Crosshair->setEnabled(false); } else { m_Controls->m_Crosshair->setEnabled(true); } int width; node->GetIntProperty("shape.linewidth", width); m_Controls->m_LineWidth->setValue(width); float radius; node->GetFloatProperty("shape.tuberadius", radius); m_Controls->m_TubeWidth->setValue(radius); float range; node->GetFloatProperty("Fiber2DSliceThickness",range); mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); mitk::BaseGeometry::Pointer geo = fib->GetGeometry(); mitk::ScalarType max = geo->GetExtentInMM(0); max = std::max(max, geo->GetExtentInMM(1)); max = std::max(max, geo->GetExtentInMM(2)); m_Controls->m_FiberThicknessSlider->setMaximum(max * 10); m_Controls->m_FiberThicknessSlider->setValue(range * 10); } else if(dynamic_cast(nodeData) || dynamic_cast(nodeData) || dynamic_cast(nodeData)) { m_Controls->m_ImageControlsFrame->setVisible(true); m_Controls->m_NumberGlyphsFrame->setVisible(true); m_Controls->m_GlyphFrame->setVisible(true); m_Controls->m_NormalizationFrame->setVisible(true); if(m_NodeUsedForOdfVisualization.IsNotNull()) { m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", false); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", false); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", false); } m_NodeUsedForOdfVisualization = node; m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", m_GlyIsOn_S); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", m_GlyIsOn_C); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", m_GlyIsOn_T); if (dynamic_cast(nodeData)) { m_Controls->m_NormalizationDropdown->setVisible(false); m_Controls->m_NormalizationLabel->setVisible(false); } else { m_Controls->m_NormalizationDropdown->setVisible(true); m_Controls->m_NormalizationLabel->setVisible(true); } int val; node->GetIntProperty("ShowMaxNumber", val); m_Controls->m_ShowMaxNumber->setValue(val); m_Controls->m_NormalizationDropdown->setCurrentIndex(dynamic_cast(node->GetProperty("Normalization"))->GetValueAsId()); float fval; node->GetFloatProperty("Scaling",fval); m_Controls->m_ScalingFactor->setValue(fval); m_Controls->m_AdditionalScaling->setCurrentIndex(dynamic_cast(node->GetProperty("ScaleBy"))->GetValueAsId()); bool switchTensorViewValue = false; node->GetBoolProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", switchTensorViewValue ); bool colourisationModeBit = false; node->GetBoolProperty("DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", colourisationModeBit ); m_Controls->m_OdfColorBox->setCurrentIndex(colourisationModeBit); numOdfImages++; } else if(dynamic_cast(nodeData)) { PlanarFigureFocus(); } else if( dynamic_cast(nodeData) ) { m_Controls->m_ImageControlsFrame->setVisible(true); m_Controls->m_TSMenu->setVisible(true); } } if( nodes.empty() ) { return; } mitk::DataNode::Pointer node = nodes.at(0); if( node.IsNull() ) { return; } QMenu *myMenu = m_MyMenu; myMenu->clear(); QActionGroup* thickSlicesActionGroup = new QActionGroup(myMenu); thickSlicesActionGroup->setExclusive(true); int currentTSMode = 0; { mitk::ResliceMethodProperty::Pointer m = dynamic_cast(node->GetProperty( "reslice.thickslices" )); if( m.IsNotNull() ) currentTSMode = m->GetValueAsId(); } int maxTS = 30; for (auto node: nodes) { mitk::Image* image = dynamic_cast(node->GetData()); if (image) { int size = std::max(image->GetDimension(0), std::max(image->GetDimension(1), image->GetDimension(2))); if (size>maxTS) { maxTS=size; } } } maxTS /= 2; int currentNum = 0; { mitk::IntProperty::Pointer m = dynamic_cast(node->GetProperty( "reslice.thickslices.num" )); if( m.IsNotNull() ) { currentNum = m->GetValue(); if(currentNum < 0) { currentNum = 0; } if(currentNum > maxTS) { currentNum = maxTS; } } } if(currentTSMode==0) { currentNum=0; } QSlider *m_TSSlider = new QSlider(myMenu); m_TSSlider->setMinimum(0); m_TSSlider->setMaximum(maxTS-1); m_TSSlider->setValue(currentNum); m_TSSlider->setOrientation(Qt::Horizontal); connect( m_TSSlider, SIGNAL( valueChanged(int) ), this, SLOT( OnTSNumChanged(int) ) ); QHBoxLayout* _TSLayout = new QHBoxLayout; _TSLayout->setContentsMargins(4,4,4,4); _TSLayout->addWidget(m_TSSlider); _TSLayout->addWidget(m_TSLabel=new QLabel(QString::number(currentNum*2+1),myMenu)); QWidget* _TSWidget = new QWidget; _TSWidget->setLayout(_TSLayout); QActionGroup* thickSliceModeActionGroup = new QActionGroup(myMenu); thickSliceModeActionGroup->setExclusive(true); QWidgetAction *m_TSSliderAction = new QWidgetAction(myMenu); m_TSSliderAction->setDefaultWidget(_TSWidget); myMenu->addAction(m_TSSliderAction); QAction* mipThickSlicesAction = new QAction(myMenu); mipThickSlicesAction->setActionGroup(thickSliceModeActionGroup); mipThickSlicesAction->setText("MIP (max. intensity proj.)"); mipThickSlicesAction->setCheckable(true); mipThickSlicesAction->setChecked(currentThickSlicesMode==1); mipThickSlicesAction->setData(1); myMenu->addAction( mipThickSlicesAction ); QAction* sumThickSlicesAction = new QAction(myMenu); sumThickSlicesAction->setActionGroup(thickSliceModeActionGroup); sumThickSlicesAction->setText("SUM (sum intensity proj.)"); sumThickSlicesAction->setCheckable(true); sumThickSlicesAction->setChecked(currentThickSlicesMode==2); sumThickSlicesAction->setData(2); myMenu->addAction( sumThickSlicesAction ); QAction* weightedThickSlicesAction = new QAction(myMenu); weightedThickSlicesAction->setActionGroup(thickSliceModeActionGroup); weightedThickSlicesAction->setText("WEIGHTED (gaussian proj.)"); weightedThickSlicesAction->setCheckable(true); weightedThickSlicesAction->setChecked(currentThickSlicesMode==3); weightedThickSlicesAction->setData(3); myMenu->addAction( weightedThickSlicesAction ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); connect( thickSliceModeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(OnThickSlicesModeSelected(QAction*)) ); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_S() { m_GlyIsOn_S = m_Controls->m_VisibleOdfsON_S->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is nullptr"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", m_GlyIsOn_S); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::Visible() { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow) { m_SliceChangeListener.RenderWindowPartActivated(renderWindow); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } } void QmitkControlVisualizationPropertiesView::Hidden() { } void QmitkControlVisualizationPropertiesView::Activated() { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow) { m_SliceChangeListener.RenderWindowPartActivated(renderWindow); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } } void QmitkControlVisualizationPropertiesView::Deactivated() { } void QmitkControlVisualizationPropertiesView::FlipPeaks() { if (m_SelectedNode.IsNull() || dynamic_cast(m_SelectedNode->GetData())==nullptr) return; std::string name = m_SelectedNode->GetName(); mitk::Image::Pointer image = dynamic_cast(m_SelectedNode->GetData()); typedef mitk::ImageToItk< mitk::PeakImage::ItkPeakImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(image); caster->Update(); mitk::PeakImage::ItkPeakImageType::Pointer itkImg = caster->GetOutput(); itk::FlipPeaksFilter< float >::Pointer flipper = itk::FlipPeaksFilter< float >::New(); flipper->SetInput(itkImg); flipper->SetFlipX(m_Controls->m_FlipPeaksX->isChecked()); flipper->SetFlipY(m_Controls->m_FlipPeaksY->isChecked()); flipper->SetFlipZ(m_Controls->m_FlipPeaksZ->isChecked()); flipper->Update(); mitk::Image::Pointer resultImage = dynamic_cast(mitk::PeakImage::New().GetPointer()); mitk::CastToMitkImage(flipper->GetOutput(), resultImage); resultImage->SetVolume(flipper->GetOutput()->GetBufferPointer()); m_SelectedNode->SetData(resultImage); m_SelectedNode->SetName(name); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } +void QmitkControlVisualizationPropertiesView::Toggle3DPeaks() +{ + if (m_SelectedNode.IsNull() || dynamic_cast(m_SelectedNode->GetData())==nullptr) + return; + + bool enabled = false; + m_SelectedNode->GetBoolProperty("Enable3DPeaks", enabled); + m_SelectedNode->SetBoolProperty( "Enable3DPeaks", !enabled ); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + void QmitkControlVisualizationPropertiesView::Toggle3DClipping(bool enabled) { - if (!enabled || m_SelectedNode.IsNull() || dynamic_cast(m_SelectedNode->GetData())==nullptr) + if (!enabled || m_SelectedNode.IsNull() || (dynamic_cast(m_SelectedNode->GetData())==nullptr && dynamic_cast(m_SelectedNode->GetData())==nullptr)) return; - m_SelectedNode->SetBoolProperty( "Fiber3DClippingPlaneFlip", m_Controls->m_FlipClipBox->isChecked() ); + m_SelectedNode->SetBoolProperty( "3DClippingPlaneFlip", m_Controls->m_FlipClipBox->isChecked() ); if (m_Controls->m_Clip0->isChecked()) { - m_SelectedNode->SetIntProperty( "Fiber3DClippingPlaneId", 0 ); + m_SelectedNode->SetIntProperty( "3DClippingPlaneId", 0 ); Set3DClippingPlane(true, m_SelectedNode, ""); } else if (m_Controls->m_Clip1->isChecked()) { - m_SelectedNode->SetIntProperty( "Fiber3DClippingPlaneId", 1 ); + m_SelectedNode->SetIntProperty( "3DClippingPlaneId", 1 ); Set3DClippingPlane(false, m_SelectedNode, "axial"); } else if (m_Controls->m_Clip2->isChecked()) { - m_SelectedNode->SetIntProperty( "Fiber3DClippingPlaneId", 2 ); + m_SelectedNode->SetIntProperty( "3DClippingPlaneId", 2 ); Set3DClippingPlane(false, m_SelectedNode, "sagittal"); } else if (m_Controls->m_Clip3->isChecked()) { - m_SelectedNode->SetIntProperty( "Fiber3DClippingPlaneId", 3 ); + m_SelectedNode->SetIntProperty( "3DClippingPlaneId", 3 ); Set3DClippingPlane(false, m_SelectedNode, "coronal"); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::OnSliceChanged() { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetAll(); for (unsigned int i=0; iSize(); ++i) { mitk::DataNode::Pointer node = nodes->GetElement(i); int plane_id = -1; - node->GetIntProperty("Fiber3DClippingPlaneId", plane_id); + node->GetIntProperty("3DClippingPlaneId", plane_id); if (plane_id==1) Set3DClippingPlane(false, node, "axial"); else if (plane_id==2) Set3DClippingPlane(false, node, "sagittal"); else if (plane_id==3) Set3DClippingPlane(false, node, "coronal"); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::Set3DClippingPlane(bool disable, mitk::DataNode* node, std::string plane) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); - - if (renderWindow && node && dynamic_cast(node->GetData())) + if (renderWindow && node && (dynamic_cast(node->GetData()) || dynamic_cast(node->GetData()))) { mitk::Vector3D planeNormal; planeNormal.Fill(0.0); + mitk::Point3D planeOrigin; planeOrigin.Fill(0.0); if (!disable) { mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString(plane.c_str()))->GetSliceNavigationController(); mitk::PlaneGeometry::ConstPointer planeGeo = slicer->GetCurrentPlaneGeometry(); - - //generate according cutting planes based on the view position + planeOrigin = this->GetRenderWindowPart()->GetSelectedPosition(); planeNormal = planeGeo->GetNormal(); - - float tmp1 = planeGeo->GetOrigin()[0] * planeNormal[0]; - float tmp2 = planeGeo->GetOrigin()[1] * planeNormal[1]; - float tmp3 = planeGeo->GetOrigin()[2] * planeNormal[2]; - float distance = tmp1 + tmp2 + tmp3; //attention, correct normalvector - - planeNormal *= distance; - if (distance<0) - node->SetBoolProperty( "Fiber3DClippingPlaneSecondFlip", true ); - else - node->SetBoolProperty( "Fiber3DClippingPlaneSecondFlip", false ); } - - node->SetProperty( "Fiber3DClippingPlane", mitk::Vector3DProperty::New( planeNormal ) ); - dynamic_cast(node->GetData())->RequestUpdate(); + node->SetProperty( "3DClipping", mitk::ClippingProperty::New( planeOrigin, planeNormal ) ); + if (dynamic_cast(node->GetData())) + dynamic_cast(node->GetData())->RequestUpdate(); + else + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_T() { m_GlyIsOn_T = m_Controls->m_VisibleOdfsON_T->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is nullptr"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", m_GlyIsOn_T); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_C() { m_GlyIsOn_C = m_Controls->m_VisibleOdfsON_C->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is nullptr"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", m_GlyIsOn_C); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } bool QmitkControlVisualizationPropertiesView::IsPlaneRotated() { mitk::Image* currentImage = dynamic_cast( m_NodeUsedForOdfVisualization->GetData() ); if( currentImage == nullptr ) { MITK_ERROR << " Casting problems. Returning false"; return false; } mitk::Vector3D imageNormal0 = currentImage->GetSlicedGeometry()->GetAxisVector(0); mitk::Vector3D imageNormal1 = currentImage->GetSlicedGeometry()->GetAxisVector(1); mitk::Vector3D imageNormal2 = currentImage->GetSlicedGeometry()->GetAxisVector(2); imageNormal0.Normalize(); imageNormal1.Normalize(); imageNormal2.Normalize(); auto renderWindowPart = this->GetRenderWindowPart(); double eps = 0.000001; // for all 2D renderwindows of the render window part check alignment { mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast ( renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()->GetCurrentWorldPlaneGeometry() ); if (displayPlane.IsNull()) { return false; } mitk::Vector3D normal = displayPlane->GetNormal(); normal.Normalize(); int test = 0; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal0.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal1.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal2.GetVnlVector()))-1) > eps ) { test++; } if (test==3) { return true; } } { mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast ( renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer()->GetCurrentWorldPlaneGeometry() ); if (displayPlane.IsNull()) { return false; } mitk::Vector3D normal = displayPlane->GetNormal(); normal.Normalize(); int test = 0; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal0.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal1.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal2.GetVnlVector()))-1) > eps ) { test++; } if (test==3) { return true; } } { mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast ( renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer()->GetCurrentWorldPlaneGeometry() ); if (displayPlane.IsNull()) { return false; } mitk::Vector3D normal = displayPlane->GetNormal(); normal.Normalize(); int test = 0; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal0.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal1.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal2.GetVnlVector()))-1) > eps ) { test++; } if (test==3) { return true; } } return false; } void QmitkControlVisualizationPropertiesView::ShowMaxNumberChanged() { int maxNr = m_Controls->m_ShowMaxNumber->value(); if ( maxNr < 1 ) { m_Controls->m_ShowMaxNumber->setValue( 1 ); maxNr = 1; } if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetIntProperty("ShowMaxNumber", maxNr); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::NormalizationDropdownChanged(int normDropdown) { typedef mitk::OdfNormalizationMethodProperty PropType; PropType::Pointer normMeth = PropType::New(); switch(normDropdown) { case 0: normMeth->SetNormalizationToMinMax(); break; case 1: normMeth->SetNormalizationToMax(); break; case 2: normMeth->SetNormalizationToNone(); break; case 3: normMeth->SetNormalizationToGlobalMax(); break; default: normMeth->SetNormalizationToMinMax(); } if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetProperty("Normalization", normMeth.GetPointer()); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::ScalingFactorChanged(double scalingFactor) { if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetFloatProperty("Scaling", scalingFactor); } if (auto renderWindowPart = this->GetRenderWindowPart()) { renderWindowPart->RequestUpdate(); } } void QmitkControlVisualizationPropertiesView::AdditionalScaling(int additionalScaling) { typedef mitk::OdfScaleByProperty PropType; PropType::Pointer scaleBy = PropType::New(); switch(additionalScaling) { case 0: scaleBy->SetScaleByNothing(); break; case 1: scaleBy->SetScaleByGFA(); //m_Controls->params_frame->setVisible(true); break; #ifdef DIFFUSION_IMAGING_EXTENDED case 2: scaleBy->SetScaleByPrincipalCurvature(); // commented in for SPIE paper, Principle curvature scaling //m_Controls->params_frame->setVisible(true); break; #endif default: scaleBy->SetScaleByNothing(); } if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetProperty("ScaleBy", scaleBy.GetPointer()); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::Fiber2DfadingEFX() { if (m_SelectedNode && dynamic_cast(m_SelectedNode->GetData()) ) { bool currentMode; m_SelectedNode->GetBoolProperty("Fiber2DfadeEFX", currentMode); m_SelectedNode->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(!currentMode)); dynamic_cast(m_SelectedNode->GetData())->RequestUpdate2D(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::FiberSlicingThickness2D() { if (m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { float fibThickness = m_Controls->m_FiberThicknessSlider->value() * 0.1; float currentThickness = 0; m_SelectedNode->GetFloatProperty("Fiber2DSliceThickness", currentThickness); if ( fabs(fibThickness-currentThickness) < 0.001 ) { return; } m_SelectedNode->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(fibThickness)); dynamic_cast(m_SelectedNode->GetData())->RequestUpdate2D(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::FiberSlicingUpdateLabel(int value) { QString label = "Range %1 mm"; label = label.arg(value * 0.1); m_Controls->label_range->setText(label); FiberSlicingThickness2D(); } void QmitkControlVisualizationPropertiesView::SetCustomColor(const itk::EventObject& /*e*/) { if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { float color[3]; m_SelectedNode->GetColor(color); mitk::FiberBundle::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); fib->SetFiberColors(color[0]*255, color[1]*255, color[2]*255); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { float color[3]; m_SelectedNode->GetColor(color); mitk::PeakImage::Pointer img = dynamic_cast(m_SelectedNode->GetData()); img->SetCustomColor(color[0]*255, color[1]*255, color[2]*255); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::ResetColoring() { if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { mitk::FiberBundle::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); fib->ColorFibersByOrientation(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { mitk::PeakImage::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); fib->ColorByOrientation(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::PlanarFigureFocus() { if(m_SelectedNode) { mitk::PlanarFigure* _PlanarFigure = 0; _PlanarFigure = dynamic_cast (m_SelectedNode->GetData()); if (_PlanarFigure && _PlanarFigure->GetPlaneGeometry()) { QmitkRenderWindow* selectedRenderWindow = 0; bool PlanarFigureInitializedWindow = false; auto renderWindowPart = this->GetRenderWindowPart(OPEN); QmitkRenderWindow* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial"); if (m_SelectedNode->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } QmitkRenderWindow* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal"); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } QmitkRenderWindow* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal"); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } QmitkRenderWindow* _3DRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d"); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, _3DRenderWindow->GetRenderer())) { selectedRenderWindow = _3DRenderWindow; } const mitk::PlaneGeometry* _PlaneGeometry = _PlanarFigure->GetPlaneGeometry(); mitk::VnlVector normal = _PlaneGeometry->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer worldGeometry1 = axialRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); mitk::PlaneGeometry::ConstPointer _Plane1 = dynamic_cast( worldGeometry1.GetPointer() ); mitk::VnlVector normal1 = _Plane1->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer worldGeometry2 = sagittalRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); mitk::PlaneGeometry::ConstPointer _Plane2 = dynamic_cast( worldGeometry2.GetPointer() ); mitk::VnlVector normal2 = _Plane2->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer worldGeometry3 = coronalRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); mitk::PlaneGeometry::ConstPointer _Plane3 = dynamic_cast( worldGeometry3.GetPointer() ); mitk::VnlVector normal3 = _Plane3->GetNormalVnl(); normal[0] = fabs(normal[0]); normal[1] = fabs(normal[1]); normal[2] = fabs(normal[2]); normal1[0] = fabs(normal1[0]); normal1[1] = fabs(normal1[1]); normal1[2] = fabs(normal1[2]); normal2[0] = fabs(normal2[0]); normal2[1] = fabs(normal2[1]); normal2[2] = fabs(normal2[2]); normal3[0] = fabs(normal3[0]); normal3[1] = fabs(normal3[1]); normal3[2] = fabs(normal3[2]); double ang1 = angle(normal, normal1); double ang2 = angle(normal, normal2); double ang3 = angle(normal, normal3); if(ang1 < ang2 && ang1 < ang3) { selectedRenderWindow = axialRenderWindow; } else { if(ang2 < ang3) { selectedRenderWindow = sagittalRenderWindow; } else { selectedRenderWindow = coronalRenderWindow; } } // make node visible if (selectedRenderWindow) { const mitk::Point3D& centerP = _PlaneGeometry->GetOrigin(); selectedRenderWindow->GetSliceNavigationController()->ReorientSlices( centerP, _PlaneGeometry->GetNormal()); } } // set interactor for new node (if not already set) mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(m_SelectedNode->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( m_SelectedNode ); } m_SelectedNode->SetProperty("planarfigure.iseditable",mitk::BoolProperty::New(true)); } } void QmitkControlVisualizationPropertiesView::SetInteractor() { // BUG 19179 // typedef std::vector Container; // Container _NodeSet = this->GetDataManagerSelection(); // mitk::DataNode* node = 0; // mitk::FiberBundle* bundle = 0; // mitk::FiberBundleInteractor::Pointer bundleInteractor = 0; // // finally add all nodes to the model // for(Container::const_iterator it=_NodeSet.begin(); it!=_NodeSet.end() // ; it++) // { // node = const_cast(*it); // bundle = dynamic_cast(node->GetData()); // if(bundle) // { // bundleInteractor = dynamic_cast(node->GetInteractor()); // if(bundleInteractor.IsNotNull()) // mitk::GlobalInteraction::GetInstance()->RemoveInteractor(bundleInteractor); // if(!m_Controls->m_Crosshair->isChecked()) // { // m_Controls->m_Crosshair->setChecked(false); // this->GetActiveStdMultiWidget()->GetRenderWindow4()->setCursor(Qt::ArrowCursor); // m_CurrentPickingNode = 0; // } // else // { // m_Controls->m_Crosshair->setChecked(true); // bundleInteractor = mitk::FiberBundleInteractor::New("FiberBundleInteractor", node); // mitk::GlobalInteraction::GetInstance()->AddInteractor(bundleInteractor); // this->GetActiveStdMultiWidget()->GetRenderWindow4()->setCursor(Qt::CrossCursor); // m_CurrentPickingNode = node; // } // } // } } void QmitkControlVisualizationPropertiesView::TubeRadiusChanged() { if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { float newRadius = m_Controls->m_TubeWidth->value(); - if (newRadius>0) - m_SelectedNode->SetBoolProperty( "light.enable_light", true); - else - m_SelectedNode->SetBoolProperty( "light.enable_light", false); m_SelectedNode->SetFloatProperty("shape.tuberadius", newRadius); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } +void QmitkControlVisualizationPropertiesView::RibbonWidthChanged() +{ + if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) + { + float newWidth = m_Controls->m_RibbonWidth->value(); + m_SelectedNode->SetFloatProperty("shape.ribbonwidth", newWidth); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } +} void QmitkControlVisualizationPropertiesView::LineWidthChanged() { - if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) + if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { - int newWidth = m_Controls->m_LineWidth->value(); - int currentWidth = 0; - m_SelectedNode->GetIntProperty("shape.linewidth", currentWidth); + auto newWidth = m_Controls->m_LineWidth->value(); + float currentWidth = 0; + m_SelectedNode->SetFloatProperty("shape.linewidth", currentWidth); if (currentWidth==newWidth) return; - m_SelectedNode->SetIntProperty("shape.linewidth", newWidth); - dynamic_cast(m_SelectedNode->GetData())->RequestUpdate(); + m_SelectedNode->SetFloatProperty("shape.linewidth", newWidth); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::Welcome() { berry::PlatformUI::GetWorkbench()->GetIntroManager() ->ShowIntro(GetSite()->GetWorkbenchWindow(), false); } void QmitkControlVisualizationPropertiesView::OnColourisationModeChanged() { if( m_SelectedNode && m_NodeUsedForOdfVisualization.IsNotNull() ) { m_SelectedNode->SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", mitk::BoolProperty::New( m_Controls->m_OdfColorBox->currentIndex() ) ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { MITK_DEBUG << "QmitkControlVisualizationPropertiesView::OnColourisationModeChanged() was called but m_NodeUsedForOdfVisualization was Null."; } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.h index be31412d47..5f16706a91 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.h @@ -1,151 +1,153 @@ /*=================================================================== 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 _QMITKControlVisualizationPropertiesView_H_INCLUDED #define _QMITKControlVisualizationPropertiesView_H_INCLUDED #include #include #include "berryISelectionListener.h" #include "berryIStructuredSelection.h" #include "berryISizeProvider.h" #include "ui_QmitkControlVisualizationPropertiesViewControls.h" #include "mitkEnumerationProperty.h" #include #include /*! * \ingroup org_mitk_gui_qt_diffusionquantification_internal * * \brief QmitkControlVisualizationPropertiesView * * Document your class here. */ class QmitkControlVisualizationPropertiesView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { friend struct CvpSelListener; // this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; QmitkControlVisualizationPropertiesView(); virtual ~QmitkControlVisualizationPropertiesView(); virtual void CreateQtPartControl(QWidget *parent) override; /// \brief Creation of the connections of main and control widget virtual void CreateConnections(); protected slots: void VisibleOdfsON_S(); void VisibleOdfsON_T(); void VisibleOdfsON_C(); void ShowMaxNumberChanged(); void NormalizationDropdownChanged(int); void ScalingFactorChanged(double); void AdditionalScaling(int); void OnThickSlicesModeSelected( QAction* action ); void OnTSNumChanged(int num); void ResetColoring(); void PlanarFigureFocus(); void Fiber2DfadingEFX(); void FiberSlicingThickness2D(); void FiberSlicingUpdateLabel(int); void LineWidthChanged(); void TubeRadiusChanged(); + void RibbonWidthChanged(); void SetInteractor(); void Toggle3DClipping(bool enabled=true); void FlipPeaks(); void Welcome(); void OnSliceChanged(); void SetColor(); + void Toggle3DPeaks(); /// \brief Slot function for switching colourisation mode of glyphs. void OnColourisationModeChanged(); protected: virtual void SetFocus() override; virtual void Activated() override; virtual void Deactivated() override; virtual void Visible() override; virtual void Hidden() override; virtual void NodeRemoved(const mitk::DataNode* node) override; /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; virtual void NodeAdded(const mitk::DataNode *node) override; void SetCustomColor(const itk::EventObject& /*e*/); bool IsPlaneRotated(); void SliceRotation(const itk::EventObject&); void Set3DClippingPlane(bool disable, mitk::DataNode *node, std::string plane); Ui::QmitkControlVisualizationPropertiesViewControls* m_Controls; QScopedPointer m_SelListener; berry::IStructuredSelection::ConstPointer m_CurrentSelection; mitk::DataNode::Pointer m_NodeUsedForOdfVisualization; QIcon* m_IconTexOFF; QIcon* m_IconTexON; QIcon* m_IconGlyOFF_T; QIcon* m_IconGlyON_T; QIcon* m_IconGlyOFF_C; QIcon* m_IconGlyON_C; QIcon* m_IconGlyOFF_S; QIcon* m_IconGlyON_S; bool m_TexIsOn; bool m_GlyIsOn_T; bool m_GlyIsOn_C; bool m_GlyIsOn_S; int currentThickSlicesMode; QLabel* m_TSLabel; QMenu* m_MyMenu; // for planarfigure and bundle handling: mitk::DataNode::Pointer m_SelectedNode; mitk::DataNode* m_CurrentPickingNode; unsigned long m_ColorPropertyObserverTag; unsigned long m_OpacityPropertyObserverTag; mitk::ColorProperty::Pointer m_Color; mitk::FloatProperty::Pointer m_Opacity; QmitkSliceNavigationListener m_SliceChangeListener; }; #endif // _QMITKControlVisualizationPropertiesView_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui index 84d90de329..987ea83471 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui @@ -1,938 +1,992 @@ QmitkControlVisualizationPropertiesViewControls 0 0 567 619 0 100 0 0 QmitkTemplate 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Multislice Projection MIP QToolButton::MenuButtonPopup Qt::NoArrow QFrame::NoFrame QFrame::Plain 0 0 0 0 Toggle visibility of ODF glyphs (axial) :/QmitkDiffusionImaging/glyphsoff_T.png :/QmitkDiffusionImaging/glyphson_T.png:/QmitkDiffusionImaging/glyphsoff_T.png true false Toggle visibility of ODF glyphs (sagittal) :/QmitkDiffusionImaging/glyphsoff_S.png :/QmitkDiffusionImaging/glyphson_S.png:/QmitkDiffusionImaging/glyphsoff_S.png true false Toggle visibility of ODF glyphs (coronal) :/QmitkDiffusionImaging/glyphsoff_C.png :/QmitkDiffusionImaging/glyphson_C.png:/QmitkDiffusionImaging/glyphsoff_C.png true false #Glyphs 9999 Qt::Horizontal 20 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Plain 0 0 0 0 ODF normalization false Min-Max Max None ODF Normalization: ODF normalization false ODF Value Principal Direction Color ODFs/Tensors by: QFrame::NoFrame QFrame::Plain 0 0 0 0 ODF Scale: false None FA/GFA * Additional scaling factor 3 999999999.000000000000000 0.100000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Reset to Default Coloring :/QmitkDiffusionImaging/color64.gif:/QmitkDiffusionImaging/color64.gif Reset to Default Coloring :/QmitkDiffusionImaging/reset.png:/QmitkDiffusionImaging/reset.png Position Crosshair by 3D-Click :/QmitkDiffusionImaging/crosshair.png:/QmitkDiffusionImaging/crosshair.png true false 2D Fiberfading on/off Qt::Horizontal 40 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 2D Clipping 100 10 10 10 Qt::Horizontal 90 0 10000 16777215 Range QFrame::NoFrame QFrame::Raised 0 0 0 0 - - - - 1 - - - 10 - - - Tube Radius - - - - Line Width - - - - 4 + 3 0.100000000000000 - - - - - - - 3D Fiber Clipping - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Sagittal - - - - + - No clipping - - - true - - - - - - - Coronal + Ribbon Width - - - Axial + + + 3 - - - - - - Flipp Clipping Direction + + 0.100000000000000 50 false false <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#ff0000;">One or more slices are rotated. ODF Visualisation is not possible in rotated planes. Use 'Reinit' on the image node to reset. </span></p></body></html> Qt::AutoText true QFrame::NoFrame QFrame::Raised 0 0 0 0 - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + QFrame::NoFrame QFrame::Raised 0 0 0 0 - + + + + y + + + + + + + z + + + + + + + x + + + + 0 0 Flip Peaks + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + - + + + Reset to Default Coloring + - x + + + + + :/QmitkDiffusionImaging/reset.png:/QmitkDiffusionImaging/reset.png - - + + + + Reset to Default Coloring + - y + + + + + :/QmitkDiffusionImaging/color64.gif:/QmitkDiffusionImaging/color64.gif - - - - z + + + + Qt::Horizontal - + + + 40 + 20 + + + - - - - Reset to Default Coloring + + + + Line Width + + + + + + + 1 + + + 1.000000000000000 + + + 0.100000000000000 + + 1.000000000000000 + + + + + + + + + + 3D Clipping + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + - + Coronal - - - :/QmitkDiffusionImaging/reset.png:/QmitkDiffusionImaging/reset.png + + + + + + Axial - - - - Reset to Default Coloring + + + + No clipping + + true + + + + + + + Sagittal + + + + + - + Flipp Clipping Direction - - - :/QmitkDiffusionImaging/color64.gif:/QmitkDiffusionImaging/color64.gif + + + + + + Enable 3D Rendering Qt::Vertical 20 40 QmitkDataStorageComboBox.h diff --git a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropper.dox b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropper.dox index 70208b09c3..62658b5368 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropper.dox +++ b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropper.dox @@ -1,37 +1,37 @@ /** \page org_mitk_gui_qt_imagecropper Image Cropper Plugin -\imageMacro{QmitkImageCropper_Icon.png,"Icon of the Image Cropper Plugin.",20} +\imageMacro{crop.svg,"Icon of the Image Cropper Plugin.",20} \tableofcontents \section org_mitk_gui_qt_imagecropperUsage Usage The Image Cropper Plugin allows to crop subvolumes out of your original image volume by defining a cubic bounding box. This box can be placed at an arbitrary position in the volume and can be easily adjusted by using the handles on each of the faces. Touching the handles changes the size of the box whereas touching the box itself changes its position. As soon as the bounding box is placed at the desired position, pressing the button 'Crop' creates a new image assigned to the original image as child node containing only the selected subvolume. The size of the subvolume equals the size of the bounding box. Pressing the "Mask" button keeps the original image size but masks out the area not contained within the bounding box bounds. In case of 3D+t images the whole time series is cropped by default. \imageMacro{BoundingBox_ImageCropperView.png,"Bounding Box.",12.00} \imageMacro{Basic_ImageCropperView.png,"Basic Settings.",7.09} \section org_mitk_gui_qt_imagecropperAdvanced Advanced settings In the advanced settings view you find additional features to manipulate the bounding box. \imageMacro{Advanced_ImageCropperView.png,"Advanced Settings.",7.09} \subsection org_mitk_gui_qt_imagecropperAdvancedOverwrite Overwrite original image By enabling this checkbox the image is replaced by the cropped subvolume. Be careful to use this option since there is no undo action available. \subsection org_mitk_gui_qt_imagecropperAdvancedTimestep Crop current time step only If this checkbox is enabled the xD + t image is reduced to a xD image (e.g., 3D+t --> 3D) with the time step visible in the widget. This is useful if you want to extract a single image or its corresponding subvolume of the time series. The whole time series is cropped by default using the timeGeometry of the time step visible in the widget. \section org_mitk_gui_qt_imagecropperIssues Current issues Cropping 2D images is not supported unless the are 3D images containing only a single slice. The user will be notified by a warning and the input is handled as a single label image. Right now changing the shape or rotation of the bounding box is not supported but might be integrated in the future. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/crop.svg b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/crop.svg new file mode 100644 index 0000000000..7abad89683 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/crop.svg @@ -0,0 +1,60 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox b/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox index 2267b623d2..e158d98694 100644 --- a/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox +++ b/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox @@ -1,15 +1,15 @@ /** \page org_mitk_views_imagenavigator The Image Navigator -\imageMacro{QmtikImageNavigator_Slider.png,"Icon of the Image Navigator",2.00} +\imageMacro{image_navigator.svg,"Icon of the Image Navigator",2.00} \imageMacro{QmtikImageNavigator_ImageNavigator.png,"Image Navigator",7.47} Fast movement through the available data can be achieved by using the Image Navigator. By moving the sliders around you can scroll quickly through the slides and timesteps. By entering numbers in the relevant fields you can jump directly to your point of interest. The "Show detail" checkbox enables you to see the world coordinates in millimetres and the index/voxel coordinates. These may be edited to jump to a specific location. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/image_navigator.svg b/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/image_navigator.svg new file mode 100644 index 0000000000..6bde98e8bc --- /dev/null +++ b/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/image_navigator.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox index f9c2915943..0de797abdb 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox @@ -1,54 +1,54 @@ /** \page org_mitk_views_imagestatistics The Image Statistics View -\imageMacro{QmitkMeasurementToolbox_ImageStatisticsIcon.png,"Icon of the Image Statistics View",2.00} +\imageMacro{bar-chart.svg,"Icon of the Image Statistics View",2.00} \section QmitkImageStatisticsUserManualSummary Summary This view provides an easy interface to quickly compute some features of a whole image or a region of interest. This document will tell you how to use this view, but it is assumed that you already know how to use MITK in general. Please see \ref QmitkImageStatisticsUserManualDetails for more detailed information on usage and supported filters. If you encounter problems using the view, please have a look at the \ref QmitkImageStatisticsUserManualTrouble page. \section QmitkImageStatisticsUserManualDetails Details Manual sections: - \ref QmitkImageStatisticsUserManualOverview - \ref QmitkImageStatisticsUserManualUsage - \ref QmitkImageStatisticsUserManualTrouble \section QmitkImageStatisticsUserManualOverview Overview This view provides an easy interface to quickly compute some features of a whole image or a region of interest. \imageMacro{QmitkMeasurementToolbox_Interface.png,"The interface",9.10} \section QmitkImageStatisticsUserManualUsage Usage After selection of an image or a binary mask of an image in the datamanager, the Image Statistics view shows some statistical information. If a mask is selected, the name of the mask and the name of the image, to which the mask is applied, are shown at the top. For time data the current time step is used for the selected mask and the selected image. If the total number of time steps on the selected mask is less than the current time step, the last time step of the mask is used. If a mask is selected, its used time step will be displayed next to its name like this: (t=0). Check "Ignore zero-valued voxels" to hide voxels with grayvalue zero. Below it is the statistics window which displays the calculated statistical features (such as mean, standard deviation...). Beneath the statistics window is the histogram window, which shows the histogram of the current selection. At top of the histogram window are two radiobuttons. Toggle one of them to either show the histogram as a barchart or as a lineplot. Use mousewheel to zoom in and out the histogram. With the left mouse button the histogram is pannable in zoomed state. If the histogram is displayed as a barchart a tooltip is available by hovering over one of the bins. A tooltip is also available, if an intesity profile is created for a path element as mask. At the bottom of each view is one button. They copy their respective data in csv format to the clipboard. \section QmitkImageStatisticsUserManualTrouble Troubleshooting No known problems. All other problems.
Please report to the MITK mailing list. See http://www.mitk.org/wiki/Mailinglist on how to do this. */ diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox index 613a057372..e7ea6bd729 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox @@ -1,126 +1,126 @@ /** \page org_mitk_views_measurement The Measurement View -\imageMacro{QmitkMeasurementToolbox_MeasurementIcon.png,"Icon of the Measurement View",2.00} +\imageMacro{measurement.svg,"Icon of the Measurement View",2.00} \section QmitkMeasurementUserManualOverview Overview The Measurement view enables the user to interact with 2D images or single slices of 3D image stacks and planar figure data types. It allows to measure distances, angels, pathes and several geometric figures on a dataset. \tableofcontents The workflow to use this view is: \imageMacro{QmitkMeasurementToolbox_Workflow.png,"",16.00} The workflow is repeatedly useable with the same or different measurement figures, which are correlated to the choosen image and can be saved together with it for future use. On pressing the Measurement icon (see picture below the page title) in the view button line the basic appearance of the view is as follws. \imageMacro{QmitkMeasurementToolbox_BasicScreenEdited.jpg,"",16.00} The standard working plane is "Axial" but the other standard viewplanes ("Saggital" and "Coronal") are also valid for measurements. To swap between the view planes refer to the application user manual. \section QmitkMeasurementUserManualFeatures Features The view as it is depicted below offers the following features in the order of apperance on the image from top to bottom: \imageMacro{QmitkMeasurementToolbox_MeasurementView.jpg,"",7.60} The first information is the selected image's name (here: DICOM-MRI-Image) followed by the measurement figures button line with the seven measurement figures. From left to right the buttons are connected with the following functions: \subsection SubOne Draw Line Draws a line between two set points and returns the distance between these points. \subsection SubTwo Draw Path Draws a path between several set points (two and more) and calculates the circumference, that is all line's length summed up. Add the final point by double left click. \subsection SubThree Draw Angle Draws two lines from three set points connected in the second set point and returns the inner angle at the second point. \subsection SubFour Draw Four Point Angle Draws two lines that may but must not intersect from four set points. The returned angle is the one depicted in the icon. \subsection SubFive Draw Circle Draws a circle by setting two points, whereas the first set point is the center and the second the radius of the circle. The measured values are the radius and the included area. \subsection SubSix Draw Rectangle Draws a rectangle by setting two points at the opposing edges of the rectangle starting with the upper left edge. The measured values are the circumference and the included area. \subsection SubSeven Draw Polygon Draws a polygon by setting three or more points. The measured values are the circumference and the included area. Add the final point by double left click. Below the buttonline the statistics window is situated, it displays the results of the actual measurements from the selected measurement figures. The content of the statistics window can be copied to the clipboard with the correspondig button for further use in a table calculation programm (e.g. Open Office Calc etc.). \imageMacro{QmitkMeasurementToolbox_ImageProcessed.jpg,"",7.56} The last row contains again a button line to swap from the measurement perspective (activated in the image) to other supported MITK perspectives. \section QmitkMeasurementUserManualUsage Usage This Section is subdivided into four subsections:
  1. Add an image
  2. Work with measurement figures
  3. Save the image with measurement information
  4. Remove measurement figures or image
Let's start with subsection 1 \subsection One Add an image There are two possible ways to add an image to the programm. One is to grap the image with left mouse click from your prefered file browser and simply drag&drop it to the View Plane field. The other way is to use the \imageMacro{QmitkMeasurementToolbox_OpenButton.png,"",2.01} button in the upper left corner of the application. A dialog window appears showing the file tree of the computer. Navigate to the wanted file and select it with the left mouse click. Afterwards just use the dialog's open button. The wanted image appears in the View Plane and in the Data Manager the images name appears as a new tree node. Now the image is loaded it can be adjusted in the usual way ( zoom in/out: right mouse button + moving the mouse up and down, moving the image: press mouse wheel and move the mouse to the wished direction, scroll through the slices( only on 3D images): scroll mouse wheel up and down). \imageMacro{QmitkMeasurementToolbox_ImageLoadedScreen.jpg,"",16.00} After the image is loaded the image's name appears in the Data Manager. By left-clicking on the image name the buttonline becomes activated. \subsection Two Work with measurement figures The measurement view comes with seven measurement figures(see picture below), that can be applied to the images. \imageMacro{QmitkMeasurementToolbox_MeasurementFigureButtonLine.jpg,"",7.22} The results of the measurement with each of these figures is shown in the statistics window and in the lower right corner of the view plane. \imageMacro{QmitkMeasurementToolbox_ImageProcessedScreen.jpg,"",6.96} When applying more then one measurement figure to the image the actual measurement figure is depicted in red and the displayed values belong to this measurement figure. All measurement figures become part of the Data Manager as a node of the image tree. \subsection Three Save the image with measurement information After applying the wanted measurement figures the entire scene consisting of the image and the measurement figures can be saved for future use. Therefore just click the right mouse button when over the image item in the Data Manager and choose the item "Save" in the opening item list. Following to that a save dialog appears where the path to the save folder can be set. Afterwards just accept your choice with the save button. \subsection Four Remove measurement figures or image If the single measurement figures or the image is not needed any longer, it can be removed solely or as an entire group. The image can't be removed without simultaneously removing all the dependent measurement figures that belong to the image tree in the Data Manager. To remove just select the wanted items in the data manager list by left-click on it or if several items wanted to be removed left click on all wanted by simultaneously holding the ctrl-button pressed. For more detailed usage of the save/remove functionality refer to the Data Manager User Manual. ",16.00} */ diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/bar-chart.svg b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/bar-chart.svg new file mode 100644 index 0000000000..a756ada699 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/bar-chart.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/measurement.svg b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/measurement.svg new file mode 100644 index 0000000000..d5e6defc77 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/measurement.svg @@ -0,0 +1,196 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox index 2cfc3a9318..cc8f00e9a7 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox +++ b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox @@ -1,64 +1,64 @@ /** \page org_mitk_gui_qt_moviemaker The Movie Maker Plugin -\imageMacro{QmitkMovieMaker_Icon.png,"Icon of the Movie Maker Plugin.",2.00} +\imageMacro{video-camera.svg,"Icon of the Movie Maker Plugin.",2.00} \tableofcontents \section org_mitk_gui_qt_moviemakerOverview Overview The Movie Maker View allows you to create basic animations of your scene and to record them to video files. Individual animations are arranged in a timeline and can be played back sequential or in parallel. The Movie Maker View uses external FFmpeg/Libav command line utilities to write compressed video files. You have to manually install either FFmpeg or Libav and set the corresponding path in "External Programs" in the MITK Workbench Preferences (Ctrl+P) in order to record your movies to video files. \imageMacro{QmitkMovieMaker_Preferences.png,"The External Programs preferences page.",12.00} \section org_mitk_gui_qt_moviemakerUsage Usage \imageMacro{QmitkMovieMaker_MovieMakerView.png,"The Movie Maker View.",16.00} To create a movie you have to add an animation to the timeline by clicking the "Add animation" button. You can choose between the available types of animations, e.g., Orbit or Slice. The timeline surrounding bottons allow you to arrange, remove, or add further animations to your movie. Each animation can be set to either begin with the previous animation, i.e., run in parallel, or to start after the previous animation, i.e., run sequential. In combination with delays, rather complex animation arrangements are possible. To set animation specific parameters, select the corresponding animation in the timeline first. You can play back, pause and stop your movie with the according controls at the bottom of the Movie Maker View. Click the "Record" button to finally record your movie to a video file with the specified number of frames per second. You have to choose the render window which you want to record. \subsection org_mitk_gui_qt_moviemakerOrbitUsage Orbit Animation The Orbit animation rotates the camera in the 3D window around the scene. Align the camera directly in the 3D window and enter the number of degrees for the orbitting. If you are planning to have a specific view in the middle of your movie you can play the movie and pause it at the specific frame of interest. Adjust the camera in the 3D window and restart the animation. \imageMacro{QmitkMovieMaker_Orbit.png,"The Orbit animation.",12.00} \subsection org_mitk_gui_qt_moviemakerSliceUsage Slice Animation The Slice animation slices through an image. You can choose the image plane (axial, sagittal, or coronal), as well as the start and end points of the slicing. Use the image navigator in the bottom left of the Workbench to get an idea of the desired values. Check "Reverse" in order to slice from the higher slice number to the lower slice number. \imageMacro{QmitkMovieMaker_Slice.png,"The Slice animation.",12.00} \subsection org_mitk_gui_qt_moviemakerTimeUsage Time Animation The Time animation steps through the individual time steps of the current scene. You can specify the range of the animated time steps. Use the image navigator in the bottom left of the Workbench to get an idea of the desired values. Check "Reverse" in order to step from later time steps to previous time steps. \imageMacro{QmitkMovieMaker_Time.gif,"The Time animation.",12.00} */ diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/video-camera.svg b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/video-camera.svg new file mode 100644 index 0000000000..ebf0fd1bfd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/video-camera.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/multilabelsegmentation.svg b/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/multilabelsegmentation.svg new file mode 100644 index 0000000000..9b24feb3b2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/multilabelsegmentation.svg @@ -0,0 +1,10683 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/org_mitk_gui_qt_multilabelsegmentation.dox b/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/org_mitk_gui_qt_multilabelsegmentation.dox index 77069cfa4b..a88b5f28fe 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/org_mitk_gui_qt_multilabelsegmentation.dox +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/org_mitk_gui_qt_multilabelsegmentation.dox @@ -1,114 +1,114 @@ /** \page org_mitk_views_multilabelsegmentation The Multilabel Segmentation View -\imageMacro{"multilabelsegmentation.png", "html", 12} +\imageMacro{"multilabelsegmentation.svg", "Icon of the MultiLabelSegmentation Plugin", 12} Please reference \ref org_mitk_views_segmentation for the description of the general segmentation tools. \tableofcontents \section org_mitk_views_multilabelsegmentationUserManualCreateOpenSaveImportAdd Start Segmenting To start using the Segmentation Perspective you will have to either create a new segmentation session or load an existing one from disk. The Segmentation toolbar collects buttons for the these actions: \imageMacro{"org_mitk_views_multilabelsegmentationIMGtoolbar.png", "Segmentation toolbar", 12}
  • Create segmentation session
  • a new segmentation session is created.
  • Load segmentation session
  • a segmentation session can be loaded from disk (.lset file extensions).
  • Save segmentation session
  • the current segmentation session can be saved to disk.
  • Import segmentation session
  • a segmentation session can be incorporated into the current one. All new labels will be appended at the end of the table.
  • Add label
  • a new label is appended to the current segmentation session, at the end of the table.
\section org_mitk_views_multilabelsegmentationUserManualLabelTable The Label Table The following label properties are readily available to modify:
  • Name
  • the name of the label. Can be a predefined one or any other.
  • Color
  • the color of the label.
  • Visible
  • whether the label is currently visible or hiden.
  • Locked
  • whether the label is locked or editable. A locked label cannot be overwritten by another.
The Label Table is shown below: \imageMacro{"org_mitk_views_multilabelsegmentationIMGlabeltable.png", "The Label Table showing all the labels in the current segmentation session", 12} \section org_mitk_views_multilabelsegmentationUserManualLabelCreation Creating a New Label Click the "New Label" button to add a new label. A dialog will show-up to enter the name and color. Preset organ names and corresponding colors are offered while you type in, but you can set any name. The new name if not known will be automatically remembered and made available the next time you create a new label. In the current implementation of the plugin, the maximum number of labels is restricted to 255. If you need more, you will have to create a new segmentation session. \section org_mitk_views_multilabelsegmentationUserManualLayerCreation Creating a New Layer A layer is a set of labels that occupy a non-overlapping anatomical space. The best way to describe them is by a real use case. Imagine you are working on a radiotherpay planning application. In the first layer of your segmentation session you would like to trace the contours of the liver and neighboring organs. You can accomodate all these segmentations in separate labels because they all occupy different anamical regions and do not overlap. Now say you would like to segment the arteries and veins inside the liver. If you don´t trace them in a different layer, you will overwrite the previous ones. You may also need a third layer for segmenting the different irrigation territories in the liver and a fourth layer to contain the lession you would like to treat. The next figure illustrates the Layer Manager . The buttons in it contained serve for adding a new layer, selecting the previous and the next one. The active layer is shown together with the buttons. \imageMacro{"org_mitk_views_multilabelsegmentationIMGlayerManager.png", "Correction Tool",12} \section org_mitk_views_multilabelsegmentationUserManualLabelSearch Searching a Label It may happen that many labels (e.g. > 200) are present in a segmentation session and therefore manual searching is time consuming. The Label Search edit box allows for quickly finding the label you want. Just start writing its name and and you will get assitance for completing its name. If the label you were searching is found, press enter and it will became the active one. \imageMacro{"org_mitk_views_multilabelsegmentationIMGsearchlabel.png", "Label search", 12} \section org_mitk_views_multilabelsegmentationUserManualLabelEditing Label Editing First of all, you have to select the active label by clicking on the corresponding row in the Label Table. Only one label can be active at the time. Then you can select an editing tool in the toolbox. \section org_mitk_views_multilabelsegmentationUserManualOperationsOnLabels Operations on Labels Depending on your selection in the Label Table , several actions are offered: \subsection org_mitk_views_multilabelsegmentationUserManualOperationsOnSingleSelection Single Label Selection If you right click on any label in the table, a menu will pop-up offering the following actions to be performed on the selected label:
  • Rename...
  • : change the name and/or color of the selected label.
  • Remove label
  • : delete the selected label.
  • Erase label
  • : only clear the contents of the selected label.
  • Random color
  • : generate a surface mesh out of the selected label.
  • View only
  • : generate a mask out of the selected label. A mask is a binary image with "1" inside and "0" outside.
  • View/Hide all
  • : generate a mask out of the selected label. A mask is a binary image with "1" inside and "0" outside.
  • Lock/Unlock all
  • : generate a mask out of the selected label. A mask is a binary image with "1" inside and "0" outside.
  • Create surface
  • : generate a surface out of the selected label.
  • Create mask
  • : generate a mask out of the selected label. A mask is a binary image with "1" inside and "0" outside.
\imageMacro{"org_mitk_views_multilabelsegmentationIMGLabelTableSingleSelectionContextMenu.png", "Context menu for single label selection", 12} \subsection org_mitk_views_multilabelsegmentationUserManualOperationsOnMultipleSelection Multiple Label Selection If more than one label is selected, a different menu will show up: \imageMacro{"org_mitk_views_multilabelsegmentationIMGLabelTableMultipleSelectionContextMenu.png", "Context menu for multiple label selection", 12}
  • Merge selection on current label
  • : transfer the contents of the selected labels in the Label Table into the current one.
  • Remove selected labels
  • : delete the selected labels.
  • Erase selected labels
  • : only clear the contents of the selected labels.
  • Create a surface for each selected label
  • : generate a surface mesh out of each selected label.
  • Combine and create a surface
  • : generate a surface out of the combination of the selected labels.
  • Create a mask for each selected label
  • : generate a mask out of each selected label. A mask is a binary image with "1" inside and "0" outside.
  • Combine and create a mask
  • : generate a mask out of the combination of the selected labels.
*/ diff --git a/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteraction.dox b/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteraction.dox index 012e67114d..a65d740abe 100644 --- a/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteraction.dox +++ b/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteraction.dox @@ -1,47 +1,47 @@ /** \page org_mitk_views_pointsetinteraction The Point Set Interaction View -\imageMacro{QmitkPointSetInteraction_Icon.png,"Icon of the Point Set Interaction View",2.00} +\imageMacro{pointset_interaction.svg,"Icon of the Point Set Interaction View",2.00} Available sections: - \ref QmitkPointSetInteractionUserManualOverview - \ref QmitkPointSetInteractionUserManualDetails \section QmitkPointSetInteractionUserManualOverview Overview This view allows you to define multiple sets of points, to fill them with points and to save them in so called PointSets. \imageMacro{QmitkPointSetInteraction_Screenshot.png,"MITK with the QmitkPointSetInteraction view",16.00} This document will tell you how to use this view, but it is assumed that you already know how to navigate through the slices of an image using the four window view. Please read the application manual for more information. \section QmitkPointSetInteractionUserManualDetails Details First of all you have to select a PointSet to use this view. Therefore, you have to select the point set in the data manager. If there are currently no point sets in the data tree, you have to first add a new point set to the data tree. This is done by clicking the "Add pointset..." button. \imageMacro{QmitkPointSetInteraction_AddPointSet.png,"The Add pointset... dialog",8.64} In the pop-up dialog, you have to specify a name for the new point set. This is also the node for the new data tree item. \imageMacro{QmitkPointSetInteraction_CurrentPointSetArea.png,"The Current pointset area",6.52} The "Current pointset" area contains a list of points. Within this area, all points for the current point set node are listed. To set points you have to toggle the "Set Points" button, the leftmost of the four buttons on the bottom of the view. Points can be defined by performing a left mouse button click while holding the "Shift"-key pressed in the four window view. To erase all points from the list press the next button. The user is prompted to confirm the decision. If you want to delete only a single point, left click on it in the list and then press delete on your keyboard. With the third button, a previously saved point set can be loaded and all of its points are shown in the list and the four window view. The user is prompted to select the file to be loaded. The file extension is ".mps". On the right of this button is the save button. With this function the entire point set can be saved to the harddrive. The user is prompted to select a filename. Pointsets are saved in XML fileformat but have to have a ".mps" file extension. You can select points in the render window, if the "Set Points" button is toggled, with a left mouse button click on them. If you keep the mouse button pressed, you can move the points by moving the mouse and then releasing the mouse button. With the delete key you can remove the selected points. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/pointset_interaction.svg b/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/pointset_interaction.svg new file mode 100644 index 0000000000..969c6568aa --- /dev/null +++ b/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/pointset_interaction.svg @@ -0,0 +1,77 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation.dox b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation.dox index b769e64cd1..82afd40d2f 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation.dox +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation.dox @@ -1,317 +1,317 @@ /** \page org_mitk_views_segmentation The Segmentation Plugin -\imageMacro{QmitkSegmentation_Icon.png,"Icon of the Segmentation Plugin",2.00} +\imageMacro{segmentation.svg,"Icon of the Segmentation Plugin",2.00} Some of the features described below are closed source additions to the open source toolkit MITK and are not available in every application. \tableofcontents \section org_mitk_gui_qt_segmentationUserManualOverview Overview The Segmentation plugin allows you to create segmentations of anatomical and pathological structures in medical images of the human body. The plugin consists of a number of view which can be used for:
  • manual and (semi-)automatic segmentation of organs on CT or MR image volumes via the Segmentation View
  • segmentation postprocessing via the \subpage org_mitk_views_segmentationutilities
  • clipping of existing segmentations using a resection plane via the \subpage org_mitk_views_deformableclippingplane
\imageMacro{QmitkSegmentation_IMGApplication.png,"Segmentation Plugin consisting of the Segmentation View the Segmentation Utilities View and the Clipping Plane View", 16.00} The segmentation plugin offers a number of preferences which can be set via the MITK Workbench application preference dialog: \imageMacro{QmitkSegmentation_IMGPreferences.png,"Segmentation Plugin consisting of the Segmentation View the Segmentation Utilities View and the Clipping Plane View", 10.00} The following preferences can be set:
  • Slim view: Allows you to show or hide the tool button description of the Segmentation View
  • 2D display: Specify whether the segmentation is drawn as outline or as a transparent overlay
  • 3D display: Activate 3D volume rendering for your segmentation
  • Data node selection mode: If activated the segmentation image combo box is always sychronized with the data manager selection.
  • Smoothed surface creation: Set certain smoothing parameters for surface creation
If you wonder what segmentations are good for, we shortly revisit the concept of a segmentation here. A CT or MR image is made up of volume of physical measurements (volume elements are called voxels). In CT images, for example, the gray value of each voxel corresponds to the mass absorbtion coefficient for X-rays in this voxel, which is similar in many %parts of the human body. The gray value does not contain any further information, so the computer does not know whether a given voxel is part of the body or the background, nor can it tell a brain from a liver. However, the distinction between a foreground and a background structure is required when:
  • you want to know the volume of a given organ (the computer needs to know which %parts of the image belong to this organ)
  • you want to create 3D polygon visualizations (the computer needs to know the surfaces of structures that should be drawn)
  • as a necessary pre-processing step for therapy planning, therapy support, and therapy monitoring
Creating this distinction between foreground and background is called segmentation. The Segmentation perspective of the MITK Workbench uses a voxel based approach to segmentation, i.e. each voxel of an image must be completely assigned to either foreground or background. This is in contrast to some other applications which might use an approach based on contours, where the border of a structure might cut a voxel into two %parts. The remainder of this document will summarize the features of the Segmentation perspective and how they are used. \section org_mitk_gui_qt_segmentationUserManualTechnical Technical Issues The Segmentation perspective makes a number of assumptions. To know what this view can be used for, it will help you to know that:
  • Images must be 2D, 3D, or 3D+t
  • Images must be single-values, i.e. CT, MRI or "normal" ultrasound. Images from color doppler or photographic (RGB) images are not supported
  • Segmentations are handled as binary images of the same extent as the original image
\section org_mitk_gui_qt_segmentationUserManualImageSelection Image Selection The Segmentation perspective makes use of the Data Manager view to give you an overview of all images and segmentations. \imageMacro{QmitkSegmentation_IMGSelection.png,"Data Manager is used for selecting the current segmentation. The reference image is selected in the drop down box of the control area.",5.50} To select the reference image (e.g. the original CT/MR image) use the patient image drop down box in the control area of the Segmentation view. The segmentation image selected in the Data Manager is displayed below in the segmentation drop down box. By default the auto selection mode is enabled, which always keeps the selection of the segmentation drop down box in synch with the selection in the data manager. If you disable the auto selection mode the selection of the right segmentation image has to be done via the drop down box. If no segmentation image exists or none is selected create a new segmentation image by using the "New segmentation" button on the right of the Segmentation drop down box. Some items of the graphical user interface might be disabled when no image is selected or the selected image does not fit to the patient image's geoemtry. In any case, the application will give you hints if a selection is needed. \section org_mitk_gui_qt_segmentationUserManualToolOverview Tool overview MITK comes with a comprehensive set of segmentation tools. These tools can be differenciated between manual slice-based 2D segmentation tools and (semi-)automated 3D tools. The manual 2D tools require a big amount of user interaction and can only be applied to a single image slice whereas the 3D tools operate on the hole image. The 3D tools usually require a small amount of interaction like placin seedpoints of setting some parameters. You can switch between the different toolsets by switching the 2D/3D tab in the segmentation view. \imageMacro{QmitkSegmentation_ToolOverview.png,"An overview of the existing tools in MITK. There are interactive 2D tools as well as (semi-)automated 3D tools",5.50} \section org_mitk_gui_qt_segmentationUserManualManualKringeling Manual Contouring With manual contouring you define which voxels are part of the segmentation and which are not. This allows you to create segmentations of any structeres that you may find in an image, even if they are not part of the human body. You might also use manual contouring to correct segmentations that result from sub-optimal automatic methods. The drawback of manual contouring is that you might need to define contours on many 2D slices. However, this is moderated by the interpolation feature, which will make suggestions for a segmentation. \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling1 Creating New Segmentations Unless you want to edit existing segmentations, you have to create a new, empty segmentation before you can edit it. To do so, click the "New manual segmentation" button. Input fields will appear where you can choose a name for the new segmentation and a color for its display. Click the checkmark button to confirm or the X button to cancel the new segmentation. Notice that the input field suggests names once you %start typing and that it also suggests colors for known organ names. If you use names that are not yet known to the application, it will automatically remember these names and consider them the next time you create a new segmentation. Once you created a new segmentation, you can notice a new item with the "binary mask" icon in the Data Manager tree view. This item is automatically selected for you, allowing you to %start editing the new segmentation right away. \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling2 Selecting Segmentations for Editing As you might want to have segmentations of multiple structures in a single patient image, the application needs to know which of them to use for editing. You select a segmenation by clicking it in the tree view of Data Manager. Note that segmentations are usually displayed as sub-items of "their" patient image. In the rare case, where you need to edit a segmentation that is not displayed as a a sub-item, you can click both the original image AND the segmentation while holding down CTRL or for Mac OS X the CMD on the keyboard. When a selection is made, the Segmentation View will hide all but the selected segmentation and the corresponding original image. When there are multiple segmentations, the unselected ones will remain in the Data Manager, you can make them visible at any time by selecting them. \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling3 Selecting Editing Tools If you are familiar with the MITK Workbench, you know that clicking and moving the mouse in any of the 2D render windows will move around the crosshair that defines what part of the image is displayed. This behavior is disabled while any of the manual segmentation tools are active -- otherwise you might have a hard time concentrating on the contour you are drawing. To %start using one of the editing tools, click its button the the displayed toolbox. The selected editing tool will be active and its corresponding button will stay pressed until you click the button again. Selecting a different tool also deactivates the previous one. If you have to delineate a lot of images, you should try using shortcuts to switch tools. Just hit the first letter of each tool to activate it (A for Add, S for Subtract, etc.). \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling4 Using Editing Tools All of the editing tools work by the same principle: you use the mouse (left button) to click anywhere in a 2D window (any of the orientations axial, sagittal, or frontal), move the mouse while holding the mouse button and release to finish the editing action. Multi-step undo and redo is fully supported by all editing tools. Use the application-wide undo button in the toolbar to revert erroneous %actions. \imageMacro{QmitkSegmentation_IMGIconAddSubtract.png,"Add and Subtract Tools",7.70} Use the left mouse button to draw a closed contour. When releasing the mouse button, the contour will be added (Add tool) to or removed from (Subtract tool) the current segmentation. Hold down the CTRL / CMD key to invert the operation (this will switch tools temporarily to allow for quick corrections). \imageMacro{QmitkSegmentation_IMGIconPaintWipe.png,"Paint and Wipe Tools",7.68} Use the slider below the toolbox to change the radius of these round paintbrush tools. Move the mouse in any 2D window and press the left button to draw or erase pixels. As the Add/Subtract tools, holding CTRL / CMD while drawing will invert the current tool's behavior. \imageMacro{QmitkSegmentation_IMGIconRegionGrowing.png,"Region Growing Tool",3.81} Click at one point in a 2D slice widget to add an image region to the segmentation with the region growing tool. Moving up the cursor while holding the left mouse button widens the range for the included grey values; moving it down narrows it. Moving the mouse left and right will shift the range. Region Growing selects all pixels around the mouse cursor that have a similar gray value as the pixel below the mouse cursor. This enables you to quickly create segmentations of structures that have a good contrast to surrounding tissue, e.g. the lungs. The tool will select more or less pixels (corresponding to a changing gray value interval width) when you move the mouse up or down while holding down the left mouse button. \if THISISNOTIMPLEMENTEDATTHEMOMENT A common issue with region growing is the so called "leakage" which happens when the structure of interest is connected to other pixels, of similar gray values, through a narrow "bridge" at the border of the structure. The Region Growing tool comes with a "leakage detection/removal" feature. If leakage happens, you can left-click into the leakage region and the tool will try to automatically remove this region (see illustration below). \imageMacro{QmitkSegmentation_IMGLeakage.png,"Leakage correction feature of the Region Growing tool",11.28} \endif
\imageMacro{QmitkSegmentation_IMGIconCorrection.png,"Correction Tool",3.77} You do not have to draw a closed contour to use the Correction tool and do not need to switch between the Add and Substract tool to perform small corrective changes. The following figure shows the usage of this tool:
  • if the user draws a line which %starts and ends outside the segmenation AND it intersects no other segmentation the endpoints of the line are connected and the resulting contour is filled
  • if the user draws a line which %starts and ends outside the segmenation a part of it is cut off (left image)
  • if the line is drawn fully inside the segmentation the marked region is added to the segmentation (right image)
\imageMacro{QmitkSegmentation_IMGCorrectionActions.png,"%Actions of the Correction tool illustrated.",13.50}
\imageMacro{QmitkSegmentation_IMGIconFill.png,"Fill Tool",3.81} Left-click inside a segmentation with holes to completely fill all holes (left-click outside a segmentation). \imageMacro{QmitkSegmentation_IMGIconErase.png,"Erase Tool",3.79} This tool removes a connected part of pixels that form a segmentation. You may use it to remove so called islands (see picture) or to clear a whole slice at once (left-click outside a segmentation). \imageMacro{QmitkSegmentation_IMGIconLiveWire.png,"LiveWire Tool",3.01} The LiveWire Tool acts as a magnetic lasso with a contour snapping to edges of objects. \imageMacro{QmitkSegmentation_IMGLiveWireUsage.png,"Steps for using LiveWire Tool",16.00}
  • (1) To start the Tool you have to double click near the edge of the object you want to segment. The initial anchor point will snap to the edge within a 3x3 region.
  • (2) Move the mouse. You don't have trace the edge of the object. The contour will automatically snap to it.
  • (3) To fix a segment you can set anchor points by single left mouse button click.
  • (4) Go on with moving the mouse and setting anchor points.
  • (5) To close the contour double click on the initial anchor point.
  • (6) After closing the contour can be edited by moving, inserting and deleting anchor points.
The contour will be transfered to its binary image representation by deactivating the tool. \imageMacro{QmitkSegmentation_IMG2DFastMarchingUsage.png,"2D Fast Marching Tool",3.01} Provides a fast marching based 2D interaction segmentation tool. You start with setting seedpoints in an image slice. Via several sliders you can adapt parameters and see the fast marching result instantly. \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling5 Interpolation Creating segmentations for modern CT volumes is very time-consuming, because structures of interest can easily cover a range of 50 or more slices. The Manual Segmentation View offers two helpful features for these cases:
  • 3D Interpolation
  • 2D Interpolation

The 3D interpolation is activated by default when using the manual segmentation tools. That means if you start contouring, from the second contour onwards, the surface of the segmented area will be interpolated based on the given contour information. The interpolation works with all available manual tools. Please note that this is currently a pure mathematical interpolation, i.e. image intensity information is not taken into account. With each further contour the interpolation result will be improved, but the more contours you provide the longer the recalculation will take. To achieve an optimal interpolation result and in this way a most accurate segmentation you should try to describe the surface with sparse contours by segmenting in arbitrary oriented planes. The 3D interpolation is not meant to be used for parallel slice-wise segmentation. \imageMacro{QmitkSegmentation_3DInterpolationWrongRight.png,"3D Interpolation HowTo",16.00} You can accept the interpolation result by clicking the "Accept" - button below the tool buttons. In this case the 3D interpolation will be deactivated automatically so that the result can be postprocessed without any interpolation running in background. During recalculation the interpolated surface is blinking yellow/white. When the interpolation has finished the surface is shown yellow with a small opacity. Additional to the surface, black contours are shown in the 3D render window. They mark the positions of all the drawn contours which were used for the interpolation. You can navigate between the drawn contours by clicking on the „Position“ - Nodes in the datamanager which are located below the selected segmentation. If you don't want to see these nodes just unckeck the „Show Position Nodes“ Checkbox and these nodes will be hidden. If you want to delete a drawn contour we recommend to use the Erase-Tool since Redo/Undo is not yet working for 3D interpolation. The current state of the 3D interpolation can be saved accross application restart. Therefor just click on save project during the interpolation is active. After restarting the application and load your project you can click on "Reinit Interpolation" within the 3D interpolation GUI area.
The 2D Interpolation creates suggestions for a segmentation whenever you have a slice that
  • has got neighboring slices with segmentations (these do not need to be direct neighbors but could also be a couple of slices away) AND
  • is completely clear of a manual segmentation -- i.e. there will be no suggestion if there is even only a single pixel of segmentation in the current slice.
Interpolated suggestions are displayed in a different way than manual segmentations are, until you "accept" them as part of the segmentation. To accept single slices, click the "Accept" button below the toolbox. If you have segmented a whole organ in every-x-slice, you may also review the interpolations and then accept all of them at once by clicking "... all slices". \section org_mitk_gui_qt_segmentationUserManual3DSegmentationTools 3D Segmenation tools The 3D tools operate on the hole image and require usually a small amount of interaction like placing seed-points or specifying certain parameters. All 3D tools provide an immediate segmentation feedback, which is displayed as a transparent green overlay. For accepting a preview you have to press the "Comfirm" button of the selected tool. The following 3D tools are at your disposal: \subsection org_mitk_gui_qt_segmentationUserManual3DThresholdTool 3D Threshold tool The Thresholding tool simply applies a 3D threshold to the patient image. All pixels with values equal or above the selected threshold are labeled. You can change the threshold by either moving the slider of setting a certain value in the spinbox. \imageMacro{QmitkSegmentation_3DThresholdTool.png,"3D Threshold tool",10.00} \subsection org_mitk_gui_qt_segmentationUserManual3DULTool 3D Upper/Lower Threshold tool The Upper/Lower Thresholding tool works similar to the simple 3D threshold tool but allows you to define an upper and lower threshold. All pixels with values within this threshold intervall will be labeled \imageMacro{QmitkSegmentation_3DULThresholdTool.png,"3D Upper/Lower Threshold tool",10.00} \subsection org_mitk_gui_qt_segmentationUserManual3DOtsuTool 3D Otsu tool The 3D Otsu tool provides a more sophisticated thresholding algorithm. It allows you to define a number of regions. Based on the image histogram the pixels will then divided into different regions. There more regions you define the longer will the calculation take. \imageMacro{QmitkSegmentation_3DOtsuTool.png,"3D Otsu tool",10.00} \subsection org_mitk_gui_qt_segmentationUserManual3DFMTool 3D Fast Marching tool The 3D Fast Marching tools works similar to the 2D pendant but on the hole image. Depending on you image's size the calculation will take some time. You can interactive set the parameters of the algorithm via the tool GUI. \imageMacro{QmitkSegmentation_3DFMTool.png,"3D Fast Marching tool",10.00} \subsection org_mitk_gui_qt_segmentationUserManual3DRGTool 3D Region Growing tool The 3D Region Growing tool works similar to the 2D pendant. At the beginning you have to place a seedpoint and define a threshold intervall. If you press "Run segmentation" a preview is calculated, if the "3D preview" box is checked you will also see the result in 3D. By moving the "Adapt region growing slider" you can interactively adapt the result to you image. \imageMacro{QmitkSegmentation_3DRGTool.png,"3D Region Growing tool",10.00} +\subsection org_mitk_gui_qt_segmentationUserManual3DWatershedTool 3D Watershed tool This tool provides a watershed based segmentation algorithm. \imageMacro{QmitkSegmentation_3DWatershedTool.png,"3D Watershed tool",10.00} \subsection org_mitk_gui_qt_segmentationUserManualPickingTool Picking tool The Picking tool allows you to select islands within your segmentation. This is especially usefull if e.g. a thresholding delivered your several areas within your image but you are just interested in one special region. \imageMacro{QmitkSegmentation_PickingTool.png,"Picking tool",10.00} \section org_mitk_gui_qt_segmentationUserManualPostprocessing Things you can do with segmentations As mentioned in the introduction, segmentations are never an end in themselves. Consequently, the Segmentation view adds a couple of "post-processing" %actions to the Data Manager. These %actions are accessible through the context-menu of segmentations in Data Manager's list view \imageMacro{QmitkSegmentation_IMGDataManagerContextMenu.png,"Context menu items for segmentations.",10.58}
  • Create polygon %model applies the marching cubes algorithms to the segmentation. This polygon %model can be used for visualization in 3D or other things such as stereolithography (3D printing).
  • Create smoothed polygon %model uses smoothing in addition to the marching cubes algorithms, which creates models that do not follow the exact outlines of the segmentation, but look smoother.
  • Autocrop can save memory. Manual segmentations have the same extent as the patient image, even if the segmentation comprises only a small sub-volume. This invisible and meaningless margin is removed by autocropping.
\section QmitkSegmentation_UserManualSurfaceMasking Surface Masking You can use the surface masking tool to create binary images from a surface which is used used as a mask on an image. This task is demonstrated below: \imageMacro{QmitkSegmentation_FromSurfaceBefore.png,"Load an image and a surface.",16.00} Select the image and the surface in the corresponding drop-down boxes (both are selected automatically if there is just one image and one surface) \imageMacro{QmitkSegmentation_FromSurfaceAfter.png,"Create segmentation from surface",16.00} After clicking "Create segmentation from surface" the newly created binary image is inserted in the DataManager and can be used for further processing \section org_mitk_gui_qt_segmentationUserManualTechnicalDetail Technical Information for Developers For technical specifications see \subpage QmitkSegmentationTechnicalPage and for information on the extensions of the tools system \subpage toolextensions . */ diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentationUtilities.dox b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentationUtilities.dox index b60a39db80..65cf6d1b77 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentationUtilities.dox +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentationUtilities.dox @@ -1,62 +1,62 @@ /** \page org_mitk_views_segmentationutilities The Segmentation Utilities View -\imageMacro{SegmentationUtilities.png,"Icon of the Segmentation Utilities View",5.00} +\imageMacro{segmentation_utilities.svg,"Icon of the Segmentation Utilities View",5.00} \imageMacro{QmitkSegmentationUtilities_Overview.png,"The Segmentation Utilities view",16.00} \tableofcontents \section org_mitk_views_segmentationUtilitiesManualOverview Overview The Segmentation Utilities View allows you to postprocess existing segmentations \section org_mitk_views_segmentationUtilitiesImageSelection Image Selection Usually the data selection in the Segmentation Utilities View is done via drop down box which let you just select the appropriate data. \section org_mitk_views_segmentationUtilitiesBooleanOperations Boolean Operations Boolean operations allow you to create the
  • Union: Combines two existing segmentations
  • Intersection: Keeps just the overlapping areas of two existing segmentations
  • Difference: Subtracts one segmentation from the other
of two segmentations. The selected segmentations must have the same geometry (size, spacing, ...) \imageMacro{QmitkSegmentationUtilities_IMGBooleanOperations.png,"Boolean operations of the SegmentationUtlitiesView",6.00} \section org_mitk_views_segmentationUtilitiesImageMasking Image masking You can mask your grey value image with either an existing segmentation or a surface. The result will be an image containing only the pixels that are cover by the respective mask. \imageMacro{QmitkSegmentationUtilities_IMGImageMasking.png,"Image masking widget of the Segmentation Utilities View",6.00} \section org_mitk_views_segmentationUtilitiesMorphologicalOperators Morphological Operators The morphological operators are applied to a single segmentation image. Based on a given structuring element the underlying segmentation will be modfied. MITK provides a ball and a cross as structuring elements. The follow operators are at your disposal:
  • Dilation: Each labeled pixel within the segmentation will be dilated based on the selected structuring element
  • Erosion: Each labeled pixel within the segmentation will be eroded based on the selected structuring element
  • Opening: A dilation followed by an erosion, used for smoothing edges or eliminating small objects
  • Closing An erosion followed by an dilation, used for filling small holes
  • Fill Holes Fills bigger holes within a segmentation
\imageMacro{QmitkSegmentationUtilities_IMGMorphologicalOperators.png,"Morphological operators widget of the Segmentation Utilities View",6.00} \section org_mitk_views_segmentationUtilitiesSurfaceToImage Surface to binary image This widget lets you fill you meshes into an empty binary image. It is required that a reference grey value image is present. The created binary image will have the same geometrical properties like the reference image \imageMacro{QmitkSegmentationUtilities_IMGSurfaceToImage.png,"Surface to image widget of the Segmentation Utilities View",6.00} **/ diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation.svg b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation.svg new file mode 100644 index 0000000000..54fb2e3178 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation.svg @@ -0,0 +1,2051 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation_utilities.svg b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation_utilities.svg new file mode 100644 index 0000000000..5689bc3f3c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation_utilities.svg @@ -0,0 +1,3481 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualization.dox b/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualization.dox index 45c93fb7c7..49360ff183 100644 --- a/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualization.dox +++ b/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualization.dox @@ -1,154 +1,154 @@ /** \page org_mitk_views_volumevisualization The Volume Visualization Plugin -\imageMacro{QmitkVolumeVisualization_Icon.png,"Icon of the Volume Visualization Plugin",2.00} +\imageMacro{volume_visualization.svg,"Icon of the Volume Visualization Plugin",2.00} \tableofcontents \section QVV_Overview Overview The Volume Visualization Plugin is a basic tool for visualizing three dimensional medical images. MITK provides generic transfer function presets for medical CT data. These functions, that map the gray-value to color and opacity, can be interactively edited. Additionally, there are controls to quickly generate common used transfer function shapes like the threshold and bell curve to help identify a range of grey-values. \imageMacro{QmitkVolumeVisualization_Overview.png,"",16.00} \section QVV_EnableVRPage Enable Volume Rendering \subsection QVV_LoadingImage Loading an image into the application Load an image into the application by
  • dragging a file into the application window.
  • selecting file / load from the menu.
Volume Visualization imposes following restrictions on images:
  • It has to be a 3D-Image Scalar image, that means a normal CT or MRT.
  • 3D+T are supported for rendering, but the histograms are not computed.
  • Also be aware that volume visualization requires a huge amount of memory. Very large images may not work, unless you use the 64bit version.
\subsection QVV_EnableVR Enable Volumerendering \imageMacro{QmitkVolumeVisualization_Checkboxen.png,"",8.21} Select an image in datamanager and click on the checkbox left of "Volumerendering". Please be patient, while the image is prepared for rendering, which can take up to a half minute. \subsection QVV_LODGPU Dropdown menus for the rendering and blend modes Two dropdown menus allow selection of rendering mode (Default, RayCast, GPU) and the blend mode (Composite, Max, Min, Avg, Add). Any Volume Rendering mode requires a lot of computing resources including processor, memory and often also graphics card. The Default selection usually finds the best rendering mode for the available hardware. Alternatively, it is possible to manually specify the selections RayCast and GPU. The RayCast selection is based on CPU computation and therefore typically slow, but allows to render without hardware acceleration. The GPU selection uses computing resources on the graphics card to accelerate volume rendering. It requires a powerful graphics card and OpenGL hardware support for shaders, but achieves much higher frame rates than software-rendering. Blend modes define how the volume voxels intersected by the rendering rays are pooled. The composite mode specifies standard volume rendering, for which each voxel contributes equally with opacity and color. Other blend modes simply visualize the voxel of maximum / minimum intensity and average / add the intentities along the rendering ray. \section QVV_PresetPage Applying premade presets \subsection QVV_Preset Internal presets There are some internal presets given, that can be used with normal CT data (given in Houndsfield units). A large set of medical data has been tested with that presets, but it may not suit on some special cases. Click on the "Preset" tab for using internal or custom presets. \imageMacro{QmitkVolumeVisualization_InternalPresets.png,"",8.30}
  • "CT Generic" is the default transferfunction that is first applied.
  • "CT Black&White" does not use any colors, as it may be distracting on some data.
  • "CT Cardiac" tries to increase detail on CTs from the heart.
  • "CT Bone" emphasizes bones and shows other areas more transparent.
  • "CT Bone (Gradient)" is like "CT Bone", but shows from other organs only the surface by using the gradient.
  • "MR Generic" is the default transferfunction that we use on MRT data (which is not normalized like CT data).
  • "CT Thorax small" tries to increase detail.
  • "CT Thorax large" tries to increase detail.
\subsection QVV_CustomPreset Saving and loading custom presets After creating or editing a transferfunction (see \ref QVV_Editing or \ref QVV_ThresholdBell), the custom transferfunction can be stored and later retrieved on the filesystem. Click "Save" (respectively "Load") button to save (load) the threshold-, color- and gradient function combined in a single .xml file. \section QVV_ThresholdBell Interactively create transferfunctions Beside the possibility to directly edit the transferfunctions (\ref QVV_Editing), a one-click generation of two commonly known shapes is given. Both generators have two parameters, that can be modified by first clicking on the cross and then moving the mouse up/down and left/right. The first parameter "center" (controlled by horizontal movement of the mouse) specifies the gravalue where the center of the shape will be located. The second parameter "width" (controlled by vertical movement of the mouse) specifies the width (or steepness) of the shape. \subsection Threshold Click on the "Threshold" tab to active the threshold function generator. \imageMacro{QmitkVolumeVisualization_Threshold.png,"",8.21} A threshold shape begins with zero and raises to one across the "center" parameter. Lower widths results in steeper threshold functions. \subsection Bell Click on the "Bell" tab to active the threshold function generator. \imageMacro{QmitkVolumeVisualization_Bell.png,"",8.23} A threshold shape begins with zero and raises to one at the "center" parameter and the lowers agains to zero. The "width" parameter correspondens to the width of the bell. \section QVV_Editing Customize transferfunctions in detail \subsection QVV_Navigate Choosing grayvalue interval to edit \imageMacro{QmitkVolumeVisualization_Slider.png,"",8.23} To navigate across the grayvalue range or to zoom in some ranges use the "range"-slider. All three function editors have in common following:
  • By left-clicking a new point is added.
  • By right-clicking a point is deleted.
  • By left-clicking and holding, an exisiting point can be dragged.
  • By pressing arrow keys, the currently selected point is moved.
  • By pressing the "DELETE" key, the currently selected point is deleted.
  • Between points the transferfunctions are linear interpolated.
There are three transferfunctions to customize: \subsection QVV_GO Grayvalue -> Opacity \imageMacro{QmitkVolumeVisualization_Opacity.png,"grayvalues will be mapped to opacity.",8.04} An opacity of 0 means total transparent, an opacity of 1 means total opaque. \subsection QVV_GC Grayvalue -> Color \imageMacro{QmitkVolumeVisualization_Color.png,"grayvalues will be mapped to color.",8.81} The color transferfunction editor also allows by double-clicking a point to change its color. \subsection QVV_GGO Grayvalue and Gradient -> Opacity \imageMacro{QmitkVolumeVisualization_Gradient.png,"",8.85} Here the influence of the gradient is controllable at specific grayvalues. */ diff --git a/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/volume_visualization.svg b/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/volume_visualization.svg new file mode 100644 index 0000000000..26682d271e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/volume_visualization.svg @@ -0,0 +1,65 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/Wrapping/Common/mitk_swig_classes.i b/Wrapping/Common/mitk_swig_classes.i index 8a5e384924..e531e6fc84 100644 --- a/Wrapping/Common/mitk_swig_classes.i +++ b/Wrapping/Common/mitk_swig_classes.i @@ -1,81 +1,126 @@ // // Defining some Macros that make problems with SWIG as the // corresponding definitions are not included by default. // Luckely, these includes are not necessary for SWIG. // #define ITK_NOEXCEPT #define ITKCommon_EXPORT #define ITK_OVERRIDE #define MITKCORE_EXPORT #define MITKCLCORE_EXPORT #define MITKCLUTILITIES_EXPORT #define ITKCommon_EXPORT +#define MITKMATCHPOINTREGISTRATION_EXPORT +#define MAPDeployment_EXPORT +#define MAPAlgorithms_EXPORT #define ITKCommon_EXPORT #define ITK_FORWARD_EXPORT #define ITK_OVERRIDE #define ITK_NOEXCEPT %include %include %include %include %include %include #define DEPRECATED(func) func #undef ITK_DISALLOW_COPY_AND_ASSIGN #define ITK_DISALLOW_COPY_AND_ASSIGN(TypeName) %pythoncode %{ convertion_list = {} %} SWIG_ADD_MITK_CLASS(Object, itkObject.h, itk) SWIG_ADD_MITK_CLASS(DataObject, itkDataObject.h, itk) SWIG_ADD_MITK_CLASS(TimeGeometry, mitkTimeGeometry.h, mitk) SWIG_ADD_MITK_CLASS(ArbitraryTimeGeometry, mitkArbitraryTimeGeometry.h, mitk) SWIG_ADD_MITK_CLASS(ProportionalTimeGeometry, mitkProportionalTimeGeometry.h, mitk) SWIG_ADD_MITK_CLASS(BaseGeometry, mitkBaseGeometry.h, mitk) SWIG_ADD_MITK_CLASS(Geometry3D, mitkGeometry3D.h, mitk) SWIG_ADD_MITK_CLASS(SlicedGeometry3D, mitkSlicedGeometry3D.h, mitk) SWIG_ADD_MITK_CLASS(PlaneGeometry , mitkPlaneGeometry.h, mitk) SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(BoundingBox, mitkBaseGeometry.h, mitk) SWIG_ADD_NONOBJECT_CLASS(TimeBounds, mitkBaseGeometry.h, mitk) SWIG_ADD_NONOBJECT_CLASS(FixedArrayType, mitkBaseGeometry.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point2D, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point3D, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point4D, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point2I, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point3I, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point4I, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(VnlVector, mitkVector.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Vector2D, mitkVector.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Vector3D, mitkVector.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Vector4D, mitkVector.h, mitk) SWIG_ADD_MITK_CLASS(BaseData, mitkBaseData.h, mitk) SWIG_ADD_MITK_CLASS(SlicedData, mitkSlicedData.h, mitk) SWIG_ADD_MITK_CLASS(Image, mitkImage.h, mitk) SWIG_ADD_MITK_CLASS(PointSet, mitkPointSet.h, mitk) +// +// Phenotyping Related Classes +// SWIG_ADD_MITK_CLASS(AbstractGlobalImageFeature, mitkAbstractGlobalImageFeature.h, mitk) SWIG_ADD_MITK_CLASS(GIFImageDescriptionFeatures, mitkGIFImageDescriptionFeatures.h, mitk) SWIG_ADD_MITK_CLASS(GIFFirstOrderStatistics, mitkGIFFirstOrderStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFFirstOrderHistogramStatistics, mitkGIFFirstOrderHistogramStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFVolumetricStatistics, mitkGIFVolumetricStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFVolumetricDensityStatistics, mitkGIFVolumetricDensityStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFCooccurenceMatrix2, mitkGIFCooccurenceMatrix2.h, mitk) SWIG_ADD_MITK_CLASS(GIFNeighbouringGreyLevelDependenceFeature, mitkGIFNeighbouringGreyLevelDependenceFeatures.h, mitk) SWIG_ADD_MITK_CLASS(GIFGreyLevelRunLength, mitkGIFGreyLevelRunLength.h, mitk) SWIG_ADD_MITK_CLASS(GIFGreyLevelSizeZone, mitkGIFGreyLevelSizeZone.h, mitk) SWIG_ADD_MITK_CLASS(GIFGreyLevelDistanceZone, mitkGIFGreyLevelDistanceZone.h, mitk) SWIG_ADD_MITK_CLASS(GIFLocalIntensity, mitkGIFLocalIntensity.h, mitk) SWIG_ADD_MITK_CLASS(GIFIntensityVolumeHistogramFeatures, mitkGIFIntensityVolumeHistogramFeatures.h, mitk) SWIG_ADD_MITK_CLASS(GIFNeighbourhoodGreyToneDifferenceFeatures, mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h, mitk) -SWIG_ADD_MITK_CLASS(GIFCurvatureStatistic, mitkGIFCurvatureStatistic.h, mitk) \ No newline at end of file +SWIG_ADD_MITK_CLASS(GIFCurvatureStatistic, mitkGIFCurvatureStatistic.h, mitk) + +// +// MatchPoint Related Classes +// +MITKSWIG_ADD_CLASS(MITKAlgorithmHelper, mitkAlgorithmHelper.h, mitk) +MITKSWIG_ADD_CLASS(RegistrationType, mitkImageMappingHelper.h, mitk::ImageMappingHelper) +MITKSWIG_ADD_CLASS(MITKRegistrationType, mitkImageMappingHelper.h, mitk::ImageMappingHelper) + + +%ignore map::deployment::DLLHandle::New(const LibraryHandleType& libraryHandle, const map::algorithm::UID* pUID, const core::String& libraryFile, const core::String& profileStr); +%ignore map::deployment::DLLHandle::New(const map::algorithm::UID* pUID,const core::String& libraryFilePath,const core::String& profileStr); +%ignore map::deployment::DLLInfo::New(const map::algorithm::UID* pUID,const core::String& libraryFilePath,const core::String& profileStr); +%ignore map::deployment::DLLHandle::New; + +SWIG_ADD_MITK_CLASS_VECTORFREE(DLLDirectoryBrowser, mapDeploymentDLLDirectoryBrowser.h, ::map::deployment) +SWIG_ADD_MITK_CLASS_VECTORFREE(DLLInfo, mapDeploymentDLLInfo.h, ::map::deployment) +SWIG_ADD_MITK_CLASS_VECTORFREE(DLLHandle, mapDeploymentDLLHandle.h, ::map::deployment) +SWIG_ADD_MITK_CLASS_VECTORFREE(UID, mapUID.h, ::map::algorithm) +%{ + namespace algorithm + { + typedef map::algorithm::UID UID; + } + namespace core + { + typedef map::core::String String; + } +%} + +MITKSWIG_ADD_HEADERFILE(mapDeploymentDLLAccess.h) +SWIG_ADD_MITK_CLASS_VECTORFREE(DLLHandle, mapDeploymentDLLHandle.h, ::map::deployment) + +// SWIG_ADD_MITK_CLASS(FastSymmetricForcesDemonsMultiResDefaultRegistrationAlgorithm, mitkFastSymmetricForcesDemonsMultiResDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(LevelSetMotionMultiResDefaultRegistrationAlgorithm, mitkLevelSetMotionMultiResDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(MultiModalAffineDefaultRegistrationAlgorithm, mitkMultiModalAffineDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(MultiModalRigidDefaultRegistrationAlgorithm, mitkMultiModalRigidDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(MultiModalTransDefaultRegistrationAlgorithm, mitkMultiModalTransDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(RigidClosedFormPointsDefaultRegistrationAlgorithm, mitkRigidClosedFormPointsDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(RigidICPDefaultRegistrationAlgorithm, mitkRigidICPDefaultRegistrationAlgorithm.h, mitk) \ No newline at end of file diff --git a/Wrapping/Common/mitk_swig_macros.i b/Wrapping/Common/mitk_swig_macros.i index 5f7c949163..9938aebc28 100644 --- a/Wrapping/Common/mitk_swig_macros.i +++ b/Wrapping/Common/mitk_swig_macros.i @@ -1,196 +1,219 @@ // // This file contains macros for swig. // + + // -// SWIG_ADD_MITK_CLASS is a helper macro in order to do -// all important stuff before an mitk::Class is included. -// Requires the name of the class as it is in c++ as classname -// and the include file, in which the class is defined. -// It is assumed that the class is somehow inherited from -// mitk::BaseData, and supports smartpointers. +// MITKSWIG_ADD_HEADERFILE includes a header-file into SWIG // -%define SWIG_ADD_MITK_CLASS(classname, classinclude, nspace) +%define MITKSWIG_ADD_HEADERFILE( classinclude ) // Include the include file in the generated cpp file %{ #include < ## classinclude ## > - typedef nspace ## :: ## classname classname ## ; - using nspace ## :: ## classname ; %} // Include the given header, where the class definition is found %include < ## classinclude ## > - using nspace ##:: ## classname ; - - - // Declaring that this class is a smart-pointer class, in order to handle - // online upcasting where necessary (for example python) - %feature("smartptr", noblock=1) nspace ##:: ## classname { itk::SmartPointer } +%enddef +// +// MITKSWIG_ADD_CLASS is a helper macro in order to do +// all important stuff in order to wrap an existing +// class +// +%define MITKSWIG_ADD_CLASS(classname, classinclude, nspace) + MITKSWIG_ADD_HEADERFILE( classinclude ) + // Using class name in order to remove ambigiouties + %{ + typedef nspace ## :: ## classname classname ## ; + using nspace ## :: ## classname ; + %} + using nspace ##:: ## classname ; // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; +%enddef - // Initianziation of std. vectors containing pointers to these classes. This allows to use - // vectors of these types as target language arrays. - %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname ## ::Pointer >; - %template(Vector ## classname) std::vector< nspace ## :: ## classname ## ::Self *>; - // Defining the Smartpointer, allows easy access in target language - %template(classname ## Pointer) itk::SmartPointer; +// +// MITKSWIG_AUTOMATED_CASTING is a helper macro in order to +// provide a convinience interface for up/downcasting of +// classes +// +%define MITKSWIG_AUTOMATED_CASTING(classname, classinclude, nspace) // Define a conversion method to convert from and to types %template(ConvertTo ## classname) ConvertTo< nspace ##:: ## classname ## >; - // This extend is necessary to have the automatic cast methods available %extend itk::SmartPointer< nspace ## :: ## classname ## ::Self> { %pythoncode %{ def _GetListOfValidItems(self): return [str(k) for k in self.GetClassHierarchy() if k in convertion_list.keys() ] %} %pythoncode %{ def __getattr__(self, item): if type(item)==str: if (len(item) > 9) and ('ConvertTo' in item): searchString=item[9:] if searchString in self._GetListOfValidItems(): def func_t(): return convertion_list[searchString](self) return func_t %} %pythoncode %{ def __dir__(self): return super().__dir__() + ['ConvertTo'+k for k in self._GetListOfValidItems()] %} } %extend std::vector< nspace ## :: ## classname *>::value_type { %pythoncode %{ def _GetListOfValidItems(self): return [str(k) for k in self.GetClassHierarchy() if k in convertion_list.keys() ] %} %pythoncode %{ def __getattr__(self, item): if type(item)==str: if (len(item) > 9) and ('ConvertTo' in item): searchString=item[9:] if searchString in self._GetListOfValidItems(): def func_t(): return convertion_list[searchString](self) return func_t %} %pythoncode %{ def __dir__(self): return super().__dir__() + ['ConvertTo'+k for k in self._GetListOfValidItems()] %} } %pythoncode %{ convertion_list['classname'] = ConvertTo ## classname %} %enddef +// +// MITKSWIG_SMARTPOINTERVECTOR : Wrapper for Vectors of Smartpointer-Classes +// +%define MITKSWIG_SMARTPOINTERVECTOR(classname, classinclude, nspace) + // Initianziation of std. vectors containing pointers to these classes. This allows to use + // vectors of these types as target language arrays. + %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname ## ::Pointer >; + %template(Vector ## classname) std::vector< nspace ## :: ## classname ## ::Self *>; +%enddef // -// SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do +// MITKSWIG_POINTERVECTOR : Wrapper for Vectors of Classes +// +%define MITKSWIG_POINTERVECTOR(classname, classinclude, nspace) + // Initianziation of std. vectors containing pointers to these classes. This allows to use + // vectors of these types as target language arrays. + %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; + %template(Vector ## classname) std::vector< nspace ## :: ## classname >; +%enddef + +// +// MITKSWIG_MITKSMARTPOINTER : Wrapper for Vectors of Smartpointer-Classes +// +%define MITKSWIG_MITKSMARTPOINTER(classname, classinclude, nspace) + + // Declaring that this class is a smart-pointer class, in order to handle + // online upcasting where necessary (for example python) + %feature("smartptr", noblock=1) nspace ##:: ## classname { itk::SmartPointer } + + // Defining the Smartpointer, allows easy access in target language + %template(classname ## Pointer) itk::SmartPointer; + +%enddef + + +// +// SWIG_ADD_MITK_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // -%define SWIG_ADD_NONOBJECT_CLASS(classname, classinclude, nspace) - // Include the include file in the generated cpp file - %{ - #include < ## classinclude ## > - typedef nspace ## :: ## classname classname ## ; - using nspace ## :: ## classname ; - %} +%define SWIG_ADD_MITK_CLASS_VECTORFREE(classname, classinclude, nspace) - // Include the given header, where the class definition is found - %include < ## classinclude ## > - using nspace ##:: ## classname ; - - // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG - // ignores namespaces. This can lead to some problems with templates. - typedef nspace ## :: ## classname classname ## ; + MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) class nspace ## :: ## classname ## ; + class nspace ## :: ## classname ## ::Pointer; - // Initianziation of std. vectors containing pointers to these classes. This allows to use - // vectors of these types as target language arrays. - %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; - %template(Vector ## classname) std::vector< nspace ## :: ## classname >; + MITKSWIG_MITKSMARTPOINTER(classname, classinclude, nspace) + MITKSWIG_AUTOMATED_CASTING(classname, classinclude, nspace) %enddef +// +// SWIG_ADD_MITK_CLASS is a helper macro in order to do +// all important stuff before an mitk::Class is included. +// Requires the name of the class as it is in c++ as classname +// and the include file, in which the class is defined. +// It is assumed that the class is somehow inherited from +// mitk::BaseData, and supports smartpointers. +// +%define SWIG_ADD_MITK_CLASS(classname, classinclude, nspace) + + MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) + + class nspace ## :: ## classname ## ; + class nspace ## :: ## classname ## ::Pointer; + + MITKSWIG_MITKSMARTPOINTER(classname, classinclude, nspace) + + MITKSWIG_SMARTPOINTERVECTOR(classname, classinclude, nspace) + + MITKSWIG_AUTOMATED_CASTING(classname, classinclude, nspace) +%enddef // -// SWIG_ADD_NONOBJECT_TEMPLATECLASS is a helper macro in order to do +// SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // -%define SWIG_ADD_NONOBJECT_TEMPLATECLASS(classname, classinclude, nspace, tmplstring) - // Include the include file in the generated cpp file - %{ - #include < ## classinclude ## > - typedef nspace ## :: ## classname classname ## ; - using nspace ## :: ## classname ; - %} +%define SWIG_ADD_NONOBJECT_CLASS(classname, classinclude, nspace) - // Include the given header, where the class definition is found - %include < ## classinclude ## > - using nspace ##:: ## classname ; + MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; - %template( classname ) nspace ## :: ## tmplstring ## ; - - // Initianziation of std. vectors containing pointers to these classes. This allows to use - // vectors of these types as target language arrays. - %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; - %template(Vector ## classname) std::vector< nspace ## :: ## classname >; + class nspace ## :: ## classname ## ; + MITKSWIG_POINTERVECTOR(classname, classinclude, nspace) %enddef - - // // SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(classname, classinclude, nspace) - // Include the include file in the generated cpp file - %{ - #include < ## classinclude ## > - typedef nspace ## :: ## classname classname ## ; - using nspace ## :: ## classname ; - %} - // Include the given header, where the class definition is found - %include < ## classinclude ## > - using nspace ##:: ## classname ; + MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; // Initianziation of std. vectors containing pointers to these classes. This allows to use // vectors of these types as target language arrays. %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; %enddef diff --git a/Wrapping/Python/CMakeLists.txt b/Wrapping/Python/CMakeLists.txt index ac708a0b76..086b30dd8b 100644 --- a/Wrapping/Python/CMakeLists.txt +++ b/Wrapping/Python/CMakeLists.txt @@ -1,77 +1,77 @@ # Version 2.8.1 is the minium requirement for this script. # this is lower than the general minimum requirement. #cmake_minimum_required ( VERSION 2.8.1 FATAL_ERROR ) include(mitkTargetLinkLibrariesWithDynamicLookup) project( MITK_Python ) set(CMAKE_SHARED_LINKER_FLAGS "" CACHE INTERNAL "" FORCE) set(CMAKE_MODULE_LINKER_FLAGS "" CACHE INTERNAL "" FORCE) mitk_check_dynamic_lookup(MODULE SHARED MITK_UNDEFINED_SYMBOLS_ALLOWED ) # # Find the necessary libraries etc.. # if ( MITK_UNDEFINED_SYMBOLS_ALLOWED ) set( _QUIET_LIBRARY "QUIET" ) else() set( _QUIET_LIBRARY "REQUIRED" ) endif() find_package ( PythonInterp REQUIRED ) find_package ( PythonLibs ${_QUIET_LIBRARY} ) include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ) # # Options # option ( MITK_PYTHON_THREADS "Enable threaded python usage by unlocking the GIL." ON ) mark_as_advanced( MITK_PYTHON_THREADS ) option ( MITK_PYTHON_EGG "Add building of python eggs to the dist target." OFF ) mark_as_advanced( MITK_PYTHON_EGG ) option ( MITK_PYTHON_WHEEL "Add building of python wheels to the dist target." ON ) mark_as_advanced( MITK_PYTHON_WHEEL ) # Prepare the SWIG-File, i.e. especially add necessary include folders -mitkSwigPrepareFiles(pyMITK MITK.i "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon") +mitkSwigPrepareFiles(pyMITK MITK.i "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon;MitkMatchPointRegistration") # Add additional SWIG Parameters # These parameters depend on the target language set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_GLOBAL_FLAGS} -features autodoc=1 -keyword ) if( MITK_PYTHON_THREADS ) set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} -threads) endif() set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}) # Create the actual SWIG project swig_add_module(pyMITK python MITK.i ) -mitkSwigAddLibraryDependencies(pyMITK "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon") +mitkSwigAddLibraryDependencies(pyMITK "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon;MitkMatchPointRegistration") mitk_target_link_libraries_with_dynamic_lookup(${SWIG_MODULE_pyMITK_REAL_NAME} ${PYTHON_LIBRARIES}) if(DEFINED SKBUILD) message(WARNING "SKBuild exists") # Currently this installation install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pyMITK.py ${CMAKE_CURRENT_SOURCE_DIR}/Packaging/__init__.py # ${MITK_DOC_FILES} DESTINATION pyMITK COMPONENT Runtime ) install(TARGETS ${SWIG_MODULE_pyMITK_REAL_NAME} RUNTIME DESTINATION pyMITK LIBRARY DESTINATION pyMITK COMPONENT Runtime ) else() message(WARNING "SKBuild missing") include(LegacyPackaging.cmake) endif()