├── .gitignore ├── PETTumorSegmentationEffect ├── Testing │ └── CMakeLists.txt ├── PETTumorSegmentationEffect.png └── CMakeLists.txt ├── PETTumorSegmentation ├── Testing │ ├── CMakeLists.txt │ └── Cxx │ │ └── CMakeLists.txt ├── Resources │ ├── Icons │ │ └── PETTumorSegmentation.png │ ├── qSlicerPETTumorSegmentationModule.qrc │ └── UI │ │ ├── qSlicerPETTumorSegmentationFooBarWidget.ui │ │ └── qSlicerPETTumorSegmentationModuleWidget.ui ├── Logic │ ├── instances.inc │ ├── CMakeLists.txt │ ├── itkCloneOSFGraphFilter.txx │ ├── itkCloneOSFGraphFilter.h │ ├── itkOSFGraphSource.h │ ├── itkLOGISMOSOSFGraphSolverFilter.h │ ├── itkMeshToOSFGraphFilter.h │ ├── itkOSFGraphToOSFGraphFilter.h │ ├── itkOSFGraphToMeshFilter.h │ ├── itkCenterNormalColumnBuilderFilter.h │ ├── itkSimpleOSFGraphBuilderFilter.h │ ├── itkOSFGraphSource.txx │ ├── itkSealingSegmentationMergerImageFilter.txx │ ├── itkSealingSegmentationMergerImageFilter.h │ ├── itkLOGISMOSOSFGraphSolverFilter.txx │ ├── itkWorkers.h │ ├── itkOSFSurface.h │ ├── itkCenterNormalColumnBuilderFilter.txx │ ├── itkMeshToOSFGraphFilter.txx │ ├── itkOSFGraphToMeshFilter.txx │ ├── itkOSFGraph.h │ ├── itkSimpleOSFGraphBuilderFilter.txx │ ├── itkOSFGraphToOSFGraphFilter.txx │ ├── logismos_graph.cxx │ ├── logismos_chunk_list.hxx │ └── logismos_graph.hxx ├── MRML │ ├── CMakeLists.txt │ └── vtkMRMLPETTumorSegmentationParametersNode.h ├── CMakeLists.txt ├── qSlicerPETTumorSegmentationModule.h └── qSlicerPETTumorSegmentationModule.cxx ├── PETTumorSegmentation.png ├── SegmentEditorPETTumorSegmentationEffect ├── PETTumorEffect.png ├── CMakeLists.txt ├── SegmentationCategoryTypeModifier-HeadAndNeckCancer.json └── AnatomicRegionAndModifier-DICOM-HeadAndNeckCancer.json ├── README.md ├── Testing ├── CMakeLists.txt └── SegmentEditorPETTumorSegmentationEffectSelfTest.py ├── CMakeLists.txt └── License.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/settings.json 2 | -------------------------------------------------------------------------------- /PETTumorSegmentationEffect/Testing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # placeholder 2 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Testing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(Cxx) 2 | -------------------------------------------------------------------------------- /PETTumorSegmentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QIICR/PETTumorSegmentation/HEAD/PETTumorSegmentation.png -------------------------------------------------------------------------------- /PETTumorSegmentationEffect/PETTumorSegmentationEffect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QIICR/PETTumorSegmentation/HEAD/PETTumorSegmentationEffect/PETTumorSegmentationEffect.png -------------------------------------------------------------------------------- /SegmentEditorPETTumorSegmentationEffect/PETTumorEffect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QIICR/PETTumorSegmentation/HEAD/SegmentEditorPETTumorSegmentationEffect/PETTumorEffect.png -------------------------------------------------------------------------------- /PETTumorSegmentation/Resources/Icons/PETTumorSegmentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QIICR/PETTumorSegmentation/HEAD/PETTumorSegmentation/Resources/Icons/PETTumorSegmentation.png -------------------------------------------------------------------------------- /PETTumorSegmentation/Resources/qSlicerPETTumorSegmentationModule.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Icons/PETTumorSegmentation.png 4 | 5 | 6 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/instances.inc: -------------------------------------------------------------------------------- 1 | #include "graph.h" 2 | 3 | #ifdef _MSC_VER 4 | #pragma warning(disable: 4661) 5 | #endif 6 | 7 | // Instantiations: 8 | // IMPORTANT: 9 | // flowtype should be 'larger' than tcaptype 10 | // tcaptype should be 'larger' than captype 11 | 12 | template class Graph; 13 | template class Graph; 14 | template class Graph; 15 | template class Graph; 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PETTumorSegmentation 2 | Slicer Extension for tumor and lymph node segmentation in PET scans 3 | 4 | Documentation: https://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/PETTumorSegmentation 5 | 6 | This work is funded in part by Quantitative Imaging to Assess Response in Cancer Therapy Trials NIH grant U01-CA140206 (PIs John Buatti, Tom Casavant, Michael Graham, Milan Sonka), Quantitative Image Informatics for Cancer Research (QIICR) NIH grant U24 CA180918, and Graph-based Medical Image Segmentation in 3D and 4D NIH grant R01 EB004640 7 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Testing/Cxx/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(KIT qSlicer${MODULE_NAME}Module) 2 | 3 | #----------------------------------------------------------------------------- 4 | set(KIT_TEST_SRCS 5 | #qSlicer${MODULE_NAME}ModuleTest.cxx 6 | ) 7 | 8 | #----------------------------------------------------------------------------- 9 | slicerMacroConfigureModuleCxxTestDriver( 10 | NAME ${KIT} 11 | SOURCES ${KIT_TEST_SRCS} 12 | WITH_VTK_DEBUG_LEAKS_CHECK 13 | ) 14 | 15 | #----------------------------------------------------------------------------- 16 | #simple_test(qSlicer${MODULE_NAME}ModuleTest) 17 | -------------------------------------------------------------------------------- /SegmentEditorPETTumorSegmentationEffect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.6) 2 | 3 | #----------------------------------------------------------------------------- 4 | set(MODULE_NAME SegmentEditorPETTumorSegmentationEffect) 5 | 6 | #----------------------------------------------------------------------------- 7 | set(MODULE_PYTHON_SCRIPTS 8 | SegmentEditorPETTumor.py 9 | ) 10 | 11 | set(MODULE_PYTHON_RESOURCES 12 | PETTumorEffect.png 13 | SegmentationCategoryTypeModifier-HeadAndNeckCancer.json 14 | AnatomicRegionAndModifier-DICOM-HeadAndNeckCancer.json 15 | ) 16 | 17 | #----------------------------------------------------------------------------- 18 | SlicerMacroBuildScriptedModule( 19 | NAME SegmentEditorPETTumorSegmentationEffect 20 | SCRIPTS "${MODULE_PYTHON_SCRIPTS}" 21 | RESOURCES "${MODULE_PYTHON_RESOURCES}" 22 | #WITH_GENERIC_TESTS 23 | ) 24 | 25 | -------------------------------------------------------------------------------- /PETTumorSegmentationEffect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.6) 2 | 3 | #----------------------------------------------------------------------------- 4 | set(MODULE_NAME PETTumorSegmentationEffect) 5 | 6 | #----------------------------------------------------------------------------- 7 | set(MODULE_PYTHON_SCRIPTS 8 | PETTumorSegmentationEffect.py 9 | ) 10 | 11 | set(MODULE_PYTHON_RESOURCES 12 | PETTumorSegmentationEffect.png 13 | ) 14 | 15 | #----------------------------------------------------------------------------- 16 | SlicerMacroBuildScriptedModule( 17 | NAME PETTumorSegmentationEffect 18 | SCRIPTS "${MODULE_PYTHON_SCRIPTS}" 19 | RESOURCES "${MODULE_PYTHON_RESOURCES}" 20 | #WITH_GENERIC_TESTS 21 | ) 22 | 23 | #----------------------------------------------------------------------------- 24 | if(BUILD_TESTING) 25 | add_subdirectory(Testing) 26 | endif() 27 | 28 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Resources/UI/qSlicerPETTumorSegmentationFooBarWidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | qSlicerPETTumorSegmentationFooBarWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 103 10 | 27 11 | 12 | 13 | 14 | Foo bar 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 22 | 23 | Foo Bar 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Testing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | set(MODULE_NAME SegmentEditorPETTumorSegmentationEffectSelfTest) 3 | 4 | #----------------------------------------------------------------------------- 5 | set(MODULE_PYTHON_SCRIPTS 6 | SegmentEditorPETTumorSegmentationEffectSelfTest.py 7 | ) 8 | 9 | set(MODULE_PYTHON_RESOURCES 10 | ) 11 | 12 | #----------------------------------------------------------------------------- 13 | slicerMacroBuildScriptedModule( 14 | NAME ${MODULE_NAME} 15 | SCRIPTS ${MODULE_PYTHON_SCRIPTS} 16 | RESOURCES ${MODULE_PYTHON_RESOURCES} 17 | #WITH_GENERIC_TESTS 18 | ) 19 | 20 | #----------------------------------------------------------------------------- 21 | if(BUILD_TESTING) 22 | 23 | # Register the unittest subclass in the main script as a ctest. 24 | # Note that the test will also be available at runtime. 25 | slicer_add_python_unittest(SCRIPT ${MODULE_NAME}.py 26 | SLICER_ARGS --additional-module-paths ${DEPENDENCIES_ADDITIONAL_MODULE_PATHS}) 27 | 28 | endif() 29 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(vtkSlicer${MODULE_NAME}ModuleLogic) 2 | 3 | set(KIT ${PROJECT_NAME}) 4 | 5 | set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_LOGIC_EXPORT") 6 | 7 | set(${KIT}_INCLUDE_DIRECTORIES 8 | ${MRML_INCLUDE_DIRS} 9 | ${MRMLCore_INCLUDE_DIRS} 10 | ${Slicer_ModuleMRML_INCLUDE_DIRS} 11 | ${Slicer_Base_INCLUDE_DIRS} 12 | ) 13 | 14 | set(${KIT}_SRCS 15 | vtkSlicer${MODULE_NAME}Logic.cxx 16 | vtkSlicer${MODULE_NAME}Logic.h 17 | itkOSFGraph.h 18 | itkOSFGraph.txx 19 | itkOSFSurface.h 20 | itkOSFSurface.txx 21 | ) 22 | 23 | set(${KIT}_TARGET_LIBRARIES 24 | ${MRML_LIBRARIES} 25 | ${ITK_LIBRARIES} 26 | vtkSlicer${MODULE_NAME}ModuleMRML 27 | vtkSlicerAnnotationsModuleMRML 28 | ) 29 | 30 | #----------------------------------------------------------------------------- 31 | SlicerMacroBuildModuleLogic( 32 | NAME ${KIT} 33 | EXPORT_DIRECTIVE ${${KIT}_EXPORT_DIRECTIVE} 34 | INCLUDE_DIRECTORIES ${${KIT}_INCLUDE_DIRECTORIES} 35 | SRCS ${${KIT}_SRCS} 36 | TARGET_LIBRARIES ${${KIT}_TARGET_LIBRARIES} 37 | ) 38 | -------------------------------------------------------------------------------- /PETTumorSegmentation/MRML/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(vtkSlicer${MODULE_NAME}ModuleMRML) 2 | 3 | set(KIT ${PROJECT_NAME}) 4 | 5 | set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_MRML_EXPORT") 6 | 7 | set(${KIT}_INCLUDE_DIRECTORIES 8 | #../../../../Slicer/Modules/Scripted/EditorLib/Logic 9 | #${CMAKE_CURRENT_SOURCE_DIR}/../../../../Slicer/Modules/Scripted/EditorLib/Logic 10 | #${Slicer_SOURCE_DIR}/Modules/Scripted/EditorLib/Logic 11 | #${Slicer_binary_dir}/Slicer-build/Modules/Scripted/EditorLib/Logic/vtkImageStash.h 12 | #message(${Slicer_binary_dir}/Modules/Scripted/EditorLib/Logic/vtkImageStash.h) 13 | #${Slicer_source_dir}/Modules/Scripted/EditorLib/Logic/vtkImageStash.h 14 | # 15 | ${MRML_INCLUDE_DIRS} 16 | ${MRMLCore_INCLUDE_DIRS} 17 | ${Slicer_ModuleMRML_INCLUDE_DIRS} 18 | ${Slicer_Base_INCLUDE_DIRS} 19 | ${vtkSlicerSegmentationsModuleLogic_INCLUDE_DIRS} 20 | ${Slicer_ModuleSegmentations_INCLUDE_DIRS} 21 | ) 22 | 23 | set(${KIT}_SRCS 24 | vtkMRML${MODULE_NAME}ParametersNode.cxx 25 | ) 26 | 27 | set(${KIT}_TARGET_LIBRARIES 28 | ${MRML_LIBRARIES} 29 | vtkSlicerSegmentationsModuleLogic 30 | ${ITK_LIBRARIES} 31 | vtkSlicerMarkupsModuleMRML 32 | #vtkSlicerEditorLibModuleLogic 33 | vtkSlicerSegmentationsModuleLogic 34 | ) 35 | 36 | #----------------------------------------------------------------------------- 37 | SlicerMacroBuildModuleMRML( 38 | NAME ${KIT} 39 | EXPORT_DIRECTIVE ${${KIT}_EXPORT_DIRECTIVE} 40 | INCLUDE_DIRECTORIES ${${KIT}_INCLUDE_DIRECTORIES} 41 | SRCS ${${KIT}_SRCS} 42 | TARGET_LIBRARIES ${${KIT}_TARGET_LIBRARIES} 43 | ) 44 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkCloneOSFGraphFilter.txx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | 19 | #ifndef _itkCloneOSFGraphFilter_txx 20 | #define _itkCloneOSFGraphFilter_txx 21 | 22 | #include "itkCloneOSFGraphFilter.h" 23 | #include "itkLinearInterpolateImageFunction.h" 24 | 25 | namespace itk 26 | { 27 | 28 | //---------------------------------------------------------------------------- 29 | template 30 | void 31 | CloneOSFGraphFilter 32 | ::GenerateData() 33 | { 34 | this->CopyInputOSFGraphToOutputOSFGraphSurfaces(); 35 | this->CopyInputOSFGraphToOutputOSFGraphGraph(); 36 | this->GetOutput()->BuildGraphNodeIdentifierLookupTable(); 37 | } 38 | 39 | //---------------------------------------------------------------------------- 40 | template 41 | void 42 | CloneOSFGraphFilter 43 | ::PrintSelf(std::ostream& os, Indent indent) const 44 | { 45 | Superclass::PrintSelf(os,indent); 46 | // todo: implement 47 | } 48 | 49 | } // namespace 50 | 51 | #endif 52 | 53 | -------------------------------------------------------------------------------- /PETTumorSegmentation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | set(MODULE_NAME PETTumorSegmentation) 3 | set(MODULE_TITLE ${MODULE_NAME}) 4 | 5 | string(TOUPPER ${MODULE_NAME} MODULE_NAME_UPPER) 6 | 7 | #----------------------------------------------------------------------------- 8 | add_subdirectory(MRML) 9 | add_subdirectory(Logic) 10 | 11 | #----------------------------------------------------------------------------- 12 | set(MODULE_EXPORT_DIRECTIVE "Q_SLICER_QTMODULES_${MODULE_NAME_UPPER}_EXPORT") 13 | 14 | # Current_{source,binary} and Slicer_{Libs,Base} already included 15 | set(MODULE_INCLUDE_DIRECTORIES 16 | ${CMAKE_CURRENT_SOURCE_DIR}/Logic 17 | ${CMAKE_CURRENT_BINARY_DIR}/Logic 18 | ${CMAKE_CURRENT_SOURCE_DIR}/MRML 19 | ${CMAKE_CURRENT_BINARY_DIR}/MRML 20 | ) 21 | 22 | set(MODULE_SRCS 23 | qSlicer${MODULE_NAME}Module.cxx 24 | qSlicer${MODULE_NAME}Module.h 25 | ) 26 | 27 | set(MODULE_MOC_SRCS 28 | qSlicer${MODULE_NAME}Module.h 29 | ) 30 | 31 | set(MODULE_TARGET_LIBRARIES 32 | vtkSlicer${MODULE_NAME}ModuleMRML 33 | vtkSlicer${MODULE_NAME}ModuleLogic 34 | ) 35 | 36 | set(MODULE_RESOURCES 37 | Resources/qSlicer${MODULE_NAME}Module.qrc 38 | ) 39 | 40 | #----------------------------------------------------------------------------- 41 | slicerMacroBuildQtModule( 42 | NAME ${MODULE_NAME} 43 | TITLE ${MODULE_TITLE} 44 | EXPORT_DIRECTIVE ${MODULE_EXPORT_DIRECTIVE} 45 | INCLUDE_DIRECTORIES ${MODULE_INCLUDE_DIRECTORIES} 46 | SRCS ${MODULE_SRCS} 47 | MOC_SRCS ${MODULE_MOC_SRCS} 48 | UI_SRCS ${MODULE_UI_SRCS} 49 | TARGET_LIBRARIES ${MODULE_TARGET_LIBRARIES} 50 | RESOURCES ${MODULE_RESOURCES} 51 | WITH_GENERIC_TESTS 52 | ) 53 | 54 | #----------------------------------------------------------------------------- 55 | if(BUILD_TESTING) 56 | add_subdirectory(Testing) 57 | endif() 58 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Resources/UI/qSlicerPETTumorSegmentationModuleWidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | qSlicerPETTumorSegmentationModuleWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 525 10 | 319 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Display 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Qt::Vertical 33 | 34 | 35 | 36 | 0 37 | 0 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | qSlicerWidget 47 | QWidget 48 |
qSlicerWidget.h
49 | 1 50 |
51 | 52 | ctkCollapsibleButton 53 | QWidget 54 |
ctkCollapsibleButton.h
55 | 1 56 |
57 | 58 | qSlicerPETTumorSegmentationFooBarWidget 59 | QWidget 60 |
qSlicerPETTumorSegmentationFooBarWidget.h
61 | 1 62 |
63 |
64 | 65 | 66 |
67 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkCloneOSFGraphFilter.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkCloneOSFGraphFilter_h 19 | #define _itkCloneOSFGraphFilter_h 20 | 21 | #include "itkOSFGraphToOSFGraphFilter.h" 22 | 23 | namespace itk 24 | { 25 | 26 | /** \class CloneOSFGraphFilter 27 | * \brief Create a deep copy of an OSFGraph. 28 | * \date 12/9/2014 29 | * \author Christian Bauer 30 | * Create a deep copy of an OSFGraph. CONTINUE 31 | * Template parameters for class CloneOSFGraphFilter: 32 | * 33 | * - TOSFGraph = The graph type of the input to clone. 34 | */ 35 | template 36 | class ITK_EXPORT CloneOSFGraphFilter : public OSFGraphToOSFGraphFilter 37 | { 38 | public: 39 | using Self = CloneOSFGraphFilter; 40 | using Superclass = OSFGraphToOSFGraphFilter; 41 | using Pointer = SmartPointer< Self >; 42 | using ConstPointer = SmartPointer< const Self >; 43 | 44 | ITK_DISALLOW_COPY_AND_ASSIGN(CloneOSFGraphFilter); 45 | 46 | itkNewMacro( Self ); 47 | itkTypeMacro( CloneOSFGraphFilter, OSFGraphToOSFGraphFilter ); 48 | 49 | protected: 50 | /** Constructor for use by New() method. */ 51 | CloneOSFGraphFilter() = default; 52 | ~CloneOSFGraphFilter() override = default; 53 | void PrintSelf(std::ostream& os, Indent indent) const override; 54 | 55 | void GenerateData() override; 56 | 57 | private: 58 | 59 | }; // end class CloneOSFGraphFilter 60 | 61 | } // end namespace itk 62 | 63 | #ifndef ITK_MANUAL_INSTANTIATION 64 | #include "itkCloneOSFGraphFilter.txx" 65 | #endif 66 | 67 | #endif 68 | 69 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.9) 2 | 3 | project(PETTumorSegmentation) 4 | 5 | #----------------------------------------------------------------------------- 6 | # Extension meta-information 7 | set(EXTENSION_HOMEPAGE "https://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/PETTumorSegmentation") 8 | set(EXTENSION_CATEGORY "Segmentation") 9 | set(EXTENSION_CONTRIBUTORS "Christian Bauer (University of Iowa), Markus van Tol (University of Iowa), Andrey Fedorov (SPL), Ethan Ulrich (University of Iowa), Reinhard Beichel (University of Iowa), John Buatti (University of Iowa)") 10 | set(EXTENSION_DESCRIPTION "Tumor and lymph node segmentation in PET scans") 11 | set(EXTENSION_ICONURL "https://raw.githubusercontent.com/QIICR/PETTumorSegmentation/master/PETTumorSegmentation.png") 12 | set(EXTENSION_SCREENSHOTURLS "https://www.slicer.org/slicerWiki/images/0/04/PETTumorSegmentation_Effect_with_models.png") 13 | 14 | #----------------------------------------------------------------------------- 15 | # Extension dependencies 16 | find_package(Slicer REQUIRED) 17 | include(${Slicer_USE_FILE}) 18 | 19 | if(CMAKE_CONFIGURATION_TYPES) 20 | set(DEPENDENCIES_ADDITIONAL_MODULE_PATHS "") 21 | foreach(config ${CMAKE_CONFIGURATION_TYPES}) 22 | list(APPEND DEPENDENCIES_ADDITIONAL_MODULE_PATHS "${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_LIB_DIR}/${config}") 23 | list(APPEND DEPENDENCIES_ADDITIONAL_MODULE_PATHS "${CMAKE_BINARY_DIR}/${Slicer_QTSCRIPTEDMODULES_LIB_DIR}/${config}") 24 | list(APPEND DEPENDENCIES_ADDITIONAL_MODULE_PATHS "${CMAKE_BINARY_DIR}/${Slicer_QTLOADABLEMODULES_PYTHON_LIB_DIR}/${config}") 25 | list(APPEND DEPENDENCIES_ADDITIONAL_MODULE_PATHS "${CMAKE_BINARY_DIR}/${Slicer_QTLOADABLEMODULES_LIB_DIR}/${config}") 26 | endforeach() 27 | else() 28 | set(DEPENDENCIES_ADDITIONAL_MODULE_PATHS 29 | ${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_LIB_DIR} 30 | ${CMAKE_BINARY_DIR}/${Slicer_QTSCRIPTEDMODULES_LIB_DIR} 31 | ${CMAKE_BINARY_DIR}/${Slicer_QTLOADABLEMODULES_PYTHON_LIB_DIR} 32 | ${CMAKE_BINARY_DIR}/${Slicer_QTLOADABLEMODULES_LIB_DIR} 33 | ) 34 | endif() 35 | 36 | #----------------------------------------------------------------------------- 37 | # Extension modules 38 | add_subdirectory(PETTumorSegmentation) 39 | # add_subdirectory(PETTumorSegmentationEffect) # requires legacy Editor with got removed: https://github.com/Slicer/Slicer/commit/39283db420baf502fa99865c9d5d58d0e5295a6e 40 | add_subdirectory(SegmentEditorPETTumorSegmentationEffect) 41 | add_subdirectory(Testing) 42 | ## NEXT_MODULE 43 | 44 | #----------------------------------------------------------------------------- 45 | include(${Slicer_EXTENSION_GENERATE_CONFIG}) 46 | include(${Slicer_EXTENSION_CPACK}) 47 | -------------------------------------------------------------------------------- /PETTumorSegmentation/qSlicerPETTumorSegmentationModule.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | Portions (c) Copyright University of Iowa All Rights Reserved. 6 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved. 7 | 8 | See COPYRIGHT.txt 9 | or http://www.slicer.org/copyright/copyright.txt for details. 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | ==============================================================================*/ 18 | 19 | #ifndef __qSlicerPETTumorSegmentationModule_h 20 | #define __qSlicerPETTumorSegmentationModule_h 21 | 22 | // SlicerQt includes 23 | #include "qSlicerLoadableModule.h" 24 | 25 | #include "qSlicerPETTumorSegmentationModuleExport.h" 26 | 27 | 28 | class qSlicerPETTumorSegmentationModulePrivate; 29 | 30 | /// \ingroup Slicer_QtModules_ExtensionTemplate 31 | class Q_SLICER_QTMODULES_PETTUMORSEGMENTATION_EXPORT 32 | qSlicerPETTumorSegmentationModule 33 | : public qSlicerLoadableModule 34 | { 35 | Q_OBJECT 36 | Q_PLUGIN_METADATA(IID "org.slicer.modules.loadable.qSlicerLoadableModule/1.0"); 37 | Q_INTERFACES(qSlicerLoadableModule); 38 | 39 | public: 40 | 41 | typedef qSlicerLoadableModule Superclass; 42 | explicit qSlicerPETTumorSegmentationModule(QObject *parent=0); 43 | ~qSlicerPETTumorSegmentationModule() override; 44 | 45 | qSlicerGetTitleMacro(QTMODULE_TITLE); 46 | 47 | QString helpText() const override; 48 | QString acknowledgementText() const override; 49 | QStringList contributors() const override; 50 | 51 | QIcon icon() const override; 52 | 53 | QStringList categories() const override; 54 | QStringList dependencies() const override; 55 | bool isHidden() const override; 56 | 57 | protected: 58 | 59 | /// Initialize the module. Register the volumes reader/writer 60 | void setup() override; 61 | 62 | /// Create and return the widget representation associated to this module 63 | qSlicerAbstractModuleRepresentation * createWidgetRepresentation() override; 64 | 65 | /// Create and return the logic associated to this module 66 | vtkMRMLAbstractLogic* createLogic() override; 67 | 68 | protected: 69 | QScopedPointer d_ptr; 70 | 71 | private: 72 | Q_DECLARE_PRIVATE(qSlicerPETTumorSegmentationModule); 73 | Q_DISABLE_COPY(qSlicerPETTumorSegmentationModule); 74 | 75 | }; 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /SegmentEditorPETTumorSegmentationEffect/SegmentationCategoryTypeModifier-HeadAndNeckCancer.json: -------------------------------------------------------------------------------- 1 | { 2 | "SegmentationCategoryTypeContextName": "Segmentation category and type - Head and Neck Cancer", 3 | "@schema": "https://raw.githubusercontent.com/qiicr/dcmqi/master/doc/segment-context-schema.json#", 4 | "SegmentationCodes": { 5 | "Category": [ 6 | { 7 | "cid": "7150", 8 | "CodingSchemeDesignator": "SRT", 9 | "CodeMeaning": "Morphologically Altered Structure", 10 | "showAnatomy": true, 11 | "CodeValue": "M-01000", 12 | "contextGroupName": "SegmentationPropertyCategories", 13 | "Type": [ 14 | { 15 | "recommendedDisplayRGBValue": [ 16 | 0, 17 | 255, 18 | 0 19 | ], 20 | "cid": "7159", 21 | "CodingSchemeDesignator": "SRT", 22 | "CodeMeaning": "Neoplasm, Primary", 23 | "UMLSConceptUID": "C1306459", 24 | "CodeValue": "M-80003", 25 | "contextGroupName": "LesionSegmentationTypes", 26 | "SNOMEDCTConceptID": "86049000" 27 | }, 28 | { 29 | "recommendedDisplayRGBValue": [ 30 | 255, 31 | 255, 32 | 0 33 | ], 34 | "cid": "7159", 35 | "CodingSchemeDesignator": "SRT", 36 | "CodeMeaning": "Neoplasm, Secondary", 37 | "UMLSConceptUID": "C2939419", 38 | "CodeValue": "M-80006", 39 | "contextGroupName": "LesionSegmentationTypes", 40 | "SNOMEDCTConceptID": "14799000" 41 | }, 42 | { 43 | "recommendedDisplayRGBValue": [ 44 | 255, 45 | 0, 46 | 0 47 | ], 48 | "cid": "7159", 49 | "CodingSchemeDesignator": "SRT", 50 | "CodeMeaning": "Neoplasm", 51 | "UMLSConceptUID": "C0027651", 52 | "CodeValue": "M-8FFFF", 53 | "contextGroupName": "LesionSegmentationTypes", 54 | "SNOMEDCTConceptID": "108369006" 55 | } 56 | ] 57 | }, 58 | { 59 | "cid": "7150", 60 | "CodingSchemeDesignator": "SRT", 61 | "showAnatomy": true, 62 | "CodeMeaning": "Spatial and Relational Concept", 63 | "CodeValue": "R-42018", 64 | "contextGroupName": "SegmentationPropertyCategories", 65 | "Type": [ 66 | { 67 | "recommendedDisplayRGBValue": [ 68 | 0, 69 | 0, 70 | 255 71 | ], 72 | "cid": "7165", 73 | "CodingSchemeDesignator": "NCIt", 74 | "CodeMeaning": "Reference Region", 75 | "UMLSConceptUID": "C2986814", 76 | "CodeValue": "C94970", 77 | "contextGroupName": "AbstractSegmentationTypes", 78 | "SNOMEDCTConceptID": "C2986814" 79 | } 80 | ] 81 | } 82 | ] 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkOSFGraphSource.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkOSFGraphSource_h 19 | #define _itkOSFGraphSource_h 20 | 21 | #include 22 | #include "itkOSFGraph.h" 23 | 24 | namespace itk 25 | { 26 | /**\class OSFGraphSource 27 | * \brief The superclass for all objects that generate an OSF graph object. 28 | * \date 12/9/2014 29 | * \author Christian Bauer 30 | * The superclass for all objects that generate an OSF graph object. CONTINUE 31 | * Template parameters for class OSFGraphSource: 32 | * 33 | * - TOutputOSFGraph = The type of OSF graph produced by the object. 34 | * 35 | */ 36 | 37 | template 38 | class ITK_EXPORT OSFGraphSource : public ProcessObject 39 | { 40 | public: 41 | using Self = OSFGraphSource; 42 | using Superclass = ProcessObject; 43 | using Pointer = SmartPointer< Self >; 44 | using ConstPointer = SmartPointer< const Self >; 45 | 46 | ITK_DISALLOW_COPY_AND_ASSIGN(OSFGraphSource); 47 | 48 | itkNewMacro( Self ); 49 | itkTypeMacro( OSFGraphSource, ProcessObject ); 50 | 51 | /** Some convenient type aliases. */ 52 | //using DataObjectPointer = DataObject::Pointer ; 53 | using OutputOSFGraphType = TOutputOSFGraph; 54 | using OutputOSFGraphPointer = typename OutputOSFGraphType::Pointer; 55 | 56 | /** Get the mesh output of this process object. */ 57 | OutputOSFGraphType* GetOutput(void); 58 | OutputOSFGraphType* GetOutput(unsigned int idx); 59 | 60 | /** Graft the specified data object onto this ProcessObject's 61 | * output. */ 62 | virtual void GraftOutput(DataObject *output); 63 | virtual void GraftNthOutput(unsigned int idx, DataObject *output); 64 | 65 | /** Make a DataObject of the correct type to be used as the specified 66 | * output. */ 67 | using Superclass::MakeOutput; 68 | ProcessObject::DataObjectPointer MakeOutput(ProcessObject::DataObjectPointerArraySizeType idx) override; 69 | 70 | //virtual void Update(); 71 | 72 | protected: 73 | /** Constructor for use by New() method. */ 74 | OSFGraphSource(); 75 | ~OSFGraphSource() override = default; 76 | void PrintSelf(std::ostream& os, Indent indent) const override; 77 | 78 | void GenerateInputRequestedRegion() override; 79 | 80 | private: 81 | 82 | }; // end class OSFGraphSource 83 | 84 | } // end namespace itk 85 | 86 | #ifndef ITK_MANUAL_INSTANTIATION 87 | #include "itkOSFGraphSource.txx" 88 | #endif 89 | 90 | #endif 91 | 92 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkLOGISMOSOSFGraphSolverFilter.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkLOGISMOSOSFGraphSolverFilter_h 19 | #define _itkLOGISMOSOSFGraphSolverFilter_h 20 | 21 | #include "itkOSFGraphToOSFGraphFilter.h" 22 | #include "logismos_graph.hxx" 23 | 24 | namespace itk 25 | { 26 | 27 | /**\class LOGISMOSOSFGraphSolverFilter 28 | * \brief 29 | * \date 12/9/2014 30 | * \author Christian Bauer 31 | * An object that applies the solver to the maximum flow graph generated by the graph builder. CONTINUE 32 | * Template parameters for class LOGISMOSOSFGraphSolverFilter: 33 | * 34 | * - TInputOSFGraph = The type of the graph input object. 35 | * - TOutputOSFGraph = The type of the graph output object. 36 | */ 37 | template 38 | class ITK_EXPORT LOGISMOSOSFGraphSolverFilter : public OSFGraphToOSFGraphFilter 39 | { 40 | public: 41 | using Self = LOGISMOSOSFGraphSolverFilter; 42 | using Superclass = OSFGraphToOSFGraphFilter; 43 | using Pointer = SmartPointer< Self >; 44 | using ConstPointer = SmartPointer< const Self >; 45 | 46 | ITK_DISALLOW_COPY_AND_ASSIGN(LOGISMOSOSFGraphSolverFilter); 47 | 48 | itkNewMacro( Self ); 49 | itkTypeMacro( LOGISMOSOSFGraphSolverFilter, OSFGraphToOSFGraphFilter ); 50 | 51 | using InputOSFGraphType = TInputOSFGraph; 52 | using InputOSFGraphConstPointer = typename InputOSFGraphType::ConstPointer; 53 | 54 | using OutputOSFGraphType = TOutputOSFGraph; 55 | using OutputOSFGraphPointer = typename OutputOSFGraphType::Pointer; 56 | 57 | protected: 58 | /** Constructor for use by New() method. */ 59 | LOGISMOSOSFGraphSolverFilter() = default; 60 | ~LOGISMOSOSFGraphSolverFilter() override; 61 | void PrintSelf(std::ostream& os, Indent indent) const override; 62 | 63 | void GenerateData() override; 64 | 65 | using CapacityType = typename InputOSFGraphType::GraphCosts; 66 | using MaxFlowGraphType = LOGISMOS::graph; 67 | using MaxFlowGraphPointer = MaxFlowGraphType*; 68 | MaxFlowGraphPointer m_MaxFlowGraph{ nullptr }; 69 | CapacityType m_FlowValue{ 0 }; 70 | virtual void BuildMaxFlowGraphGraph(); 71 | virtual void UpdateResult(); 72 | 73 | private: 74 | 75 | }; // end class LOGISMOSOSFGraphSolverFilter 76 | 77 | } // end namespace itk 78 | 79 | #ifndef ITK_MANUAL_INSTANTIATION 80 | #include "itkLOGISMOSOSFGraphSolverFilter.txx" 81 | #endif 82 | 83 | #endif 84 | 85 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkMeshToOSFGraphFilter.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkMeshToOSFGraphFilter_h 19 | #define _itkMeshToOSFGraphFilter_h 20 | 21 | #include "itkOSFGraphSource.h" 22 | 23 | namespace itk 24 | { 25 | /**\class MeshToOSFGraphFilter 26 | * \brief Converts an ITK mesh into an OSF graph of just the outer points. 27 | * \date 12/9/2014 28 | * \author Christian Bauer 29 | * Converts an ITK mesh into an OSF graph of just the outer points. CONTINUE 30 | * Template parameters for class MeshToOSFGraphFilter: 31 | * 32 | * - TInputOSFGraph = The graph type of the input to convert. 33 | * - TOutputMesh = The itk mesh type of the output after conversion. 34 | */ 35 | template 36 | class ITK_EXPORT MeshToOSFGraphFilter : public OSFGraphSource 37 | { 38 | public: 39 | using Self = MeshToOSFGraphFilter; 40 | using Superclass = OSFGraphSource; 41 | using Pointer = SmartPointer< Self >; 42 | using ConstPointer = SmartPointer< const Self >; 43 | 44 | ITK_DISALLOW_COPY_AND_ASSIGN(MeshToOSFGraphFilter); 45 | 46 | itkNewMacro( Self ); 47 | itkTypeMacro( MeshToOSFGraphFilter, OSFGraphSource ); 48 | 49 | using InputMeshType = TInputMesh; 50 | using InputMeshConstPointer = typename InputMeshType::ConstPointer; 51 | 52 | using OutputOSFGraphType = TOutputOSFGraph; 53 | using OutputOSFGraphPointer = typename OutputOSFGraphType::Pointer; 54 | 55 | using Superclass::SetInput; 56 | virtual void SetInput(unsigned int idx, const InputMeshType* input); // Set the input image of this process object. 57 | virtual const InputMeshType* GetInput(unsigned int idx); // Get the input image of this process object. 58 | virtual void SetInput(const InputMeshType* input) {this->SetInput(0, input);}; // Set the input image of this process object. 59 | virtual const InputMeshType* GetInput() {return this->GetInput(0);}; // Get the input image of this process object. 60 | 61 | OutputOSFGraphType* GetOutput(void); // Get the mesh output of this process object. 62 | virtual void GenerateOutputInformation(void); // Prepare the output 63 | using DataObjectPointerArraySizeType = typename Superclass::DataObjectPointerArraySizeType; 64 | using Superclass::MakeOutput; 65 | virtual DataObject::Pointer MakeOutput(DataObjectPointerArraySizeType idx); // create a valid output 66 | 67 | protected: 68 | /** Constructor for use by New() method. */ 69 | MeshToOSFGraphFilter(); 70 | ~MeshToOSFGraphFilter() override = default; 71 | void PrintSelf(std::ostream& os, Indent indent) const override; 72 | 73 | void GenerateData() override; 74 | virtual void CopyInputMeshToOutputOSFSurfacePoints(InputMeshConstPointer mesh, typename OutputOSFGraphType::OSFSurface::Pointer osfSurface); 75 | virtual void CopyInputMeshToOutputOSFSurfaceCells(InputMeshConstPointer mesh, typename OutputOSFGraphType::OSFSurface::Pointer osfSurface); 76 | 77 | private: 78 | 79 | }; // end class MeshToOSFGraphFilter 80 | 81 | } // end namespace itk 82 | 83 | #ifndef ITK_MANUAL_INSTANTIATION 84 | #include "itkMeshToOSFGraphFilter.txx" 85 | #endif 86 | 87 | #endif 88 | 89 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkOSFGraphToOSFGraphFilter.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkOSFGraphToOSFGraphFilter_h 19 | #define _itkOSFGraphToOSFGraphFilter_h 20 | 21 | #include "itkOSFGraphSource.h" 22 | 23 | namespace itk 24 | { 25 | 26 | /**\class SealingSegmentationMergerImageFilter 27 | * \brief 28 | * \date 12/9/2014 29 | * \author Christian Bauer 30 | * The superclass for any filter that takes one OSF graph as input and gives another as output. 31 | * By default, copies all input graph data to the output graph. 32 | * Template parameters for class SimpleOSFGraphBuilderFilter: 33 | * 34 | * - TInputOSFGraph = The graph type of the input. 35 | * - TOutputOSFGraph = The graph type of the output. 36 | */ 37 | 38 | template 39 | class ITK_EXPORT OSFGraphToOSFGraphFilter : public OSFGraphSource 40 | { 41 | public: 42 | using Self = OSFGraphToOSFGraphFilter; 43 | using Superclass = OSFGraphSource; 44 | using Pointer = SmartPointer< Self >; 45 | using ConstPointer = SmartPointer< const Self >; 46 | 47 | ITK_DISALLOW_COPY_AND_ASSIGN(OSFGraphToOSFGraphFilter); 48 | 49 | itkNewMacro( Self ); 50 | itkTypeMacro( OSFGraphToOSFGraphFilter, OSFGraphSource ); 51 | 52 | using InputOSFGraphType = TInputOSFGraph; 53 | using InputOSFGraphConstPointer = typename InputOSFGraphType::ConstPointer; 54 | 55 | using OutputOSFGraphType = TOutputOSFGraph; 56 | using OutputOSFGraphPointer = typename OutputOSFGraphType::Pointer; 57 | 58 | using Superclass::SetInput; 59 | virtual void SetInput(unsigned int idx, const InputOSFGraphType* input); // Set the input image of this process object. 60 | virtual const InputOSFGraphType* GetInput(unsigned int idx) const; // Get the input image of this process object. 61 | virtual void SetInput( const InputOSFGraphType* input) {this->SetInput(0, input);}; // Set the input image of this process object. 62 | virtual const InputOSFGraphType* GetInput() const {return this->GetInput(0);}; // Get the input image of this process object. 63 | 64 | OutputOSFGraphType* GetOutput(unsigned int idx); // Get the mesh output of this process object. 65 | OutputOSFGraphType* GetOutput(void) {return this->GetOutput(0);}; // Get the mesh output of this process object. 66 | 67 | protected: 68 | /** Constructor for use by New() method. */ 69 | OSFGraphToOSFGraphFilter(); 70 | ~OSFGraphToOSFGraphFilter() override = default; 71 | void PrintSelf(std::ostream& os, Indent indent) const override; 72 | 73 | using OSFSurface = typename OutputOSFGraphType::OSFSurface; 74 | using OSFSurfacePointer= typename OSFSurface::Pointer; 75 | using OSFSurfaceConstPointer = typename OSFSurface::ConstPointer; 76 | virtual void CopyInputOSFGraphToOutputOSFGraphSurfaces(); 77 | virtual void CopyInputOSFGraphToOutputOSFGraphSurface(OSFSurfaceConstPointer inputOSFSurface, OSFSurfacePointer outputOSFSurface); 78 | virtual void CopyInputOSFGraphToOutputOSFGraphGraph(); 79 | // todo: add more copy functions as required 80 | 81 | private: 82 | 83 | }; // end class OSFGraphToOSFGraphFilter 84 | 85 | } // end namespace itk 86 | 87 | #ifndef ITK_MANUAL_INSTANTIATION 88 | #include "itkOSFGraphToOSFGraphFilter.txx" 89 | #endif 90 | 91 | #endif 92 | 93 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkOSFGraphToMeshFilter.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef __itkOSFGraphToMeshFilter_h 19 | #define __itkOSFGraphToMeshFilter_h 20 | 21 | #include "itkMeshSource.h" 22 | 23 | namespace itk 24 | { 25 | /**\class OSFGraphToMeshFilter 26 | * \brief Converts a fully solved itk OSF graph into an itk Mesh. 27 | * \date 12/9/2014 28 | * \author Chrsitian Bauer 29 | * Converts a fully solved itk OSF graph into an itk Mesh. CONTINUE 30 | * Template parameters for class OSFGraphToMeshFilter: 31 | * 32 | * - TInputOSFGraph = The graph type of the input to convert. 33 | * - TOutputMesh = The itk mesh type of the output after conversion. 34 | */ 35 | template 36 | class ITK_EXPORT OSFGraphToMeshFilter : public MeshSource 37 | { 38 | public: 39 | /** Standard class type aliases. */ 40 | using Self = OSFGraphToMeshFilter; 41 | using Superclass = MeshSource; 42 | using Pointer = SmartPointer; 43 | using ConstPointer = SmartPointer; 44 | 45 | ITK_DISALLOW_COPY_AND_ASSIGN(OSFGraphToMeshFilter); 46 | 47 | itkNewMacro( Self ); 48 | 49 | /** Run-time type information (and related methods). */ 50 | itkTypeMacro(OSFGraphToMeshFilter, MeshSource); 51 | 52 | /** Enum defining the type of surface to extract */ 53 | enum SurfaceType { 54 | CurrentSurface, 55 | InitialSurface, 56 | InnermostSurface, 57 | OutermostSurface 58 | }; 59 | 60 | /** Get/Set the type of surface to extract */ 61 | itkSetMacro( SurfaceType, SurfaceType ); 62 | itkGetMacro( SurfaceType, SurfaceType ); 63 | 64 | /** Create a valid output. */ 65 | using DataObjectPointerArraySizeType = typename Superclass::DataObjectPointerArraySizeType; 66 | using Superclass::MakeOutput; 67 | DataObject::Pointer MakeOutput(DataObjectPointerArraySizeType idx); 68 | 69 | /** Some Image related type aliases. */ 70 | using InputOSFGraphType = TInputOSFGraph; 71 | using InputOSFGraphConstPointer = typename InputOSFGraphType::ConstPointer; 72 | 73 | /** Some Mesh related type aliases. */ 74 | using OutputMeshType = TOutputMesh; 75 | using OutputMeshPointer = typename OutputMeshType::Pointer; 76 | 77 | /** Set the input image of this process object. */ 78 | using Superclass::SetInput; 79 | void SetInput(const InputOSFGraphType* input); 80 | 81 | /** Get the input image of this process object. */ 82 | const InputOSFGraphType* GetInput(); 83 | 84 | /** Get the output Mesh of this process object. */ 85 | OutputMeshType* GetOutput(unsigned int idx); 86 | OutputMeshType* GetOutput(void) {return this->GetOutput(0);}; 87 | 88 | protected: 89 | OSFGraphToMeshFilter(); 90 | ~OSFGraphToMeshFilter() override = default; 91 | virtual void PrintSelf(std::ostream& os, Indent indent) const override; 92 | 93 | void GenerateData() override; 94 | void GenerateOutputInformation(void); 95 | virtual void CopyInputOSFSurfaceToOutputMeshPoints(typename InputOSFGraphType::OSFSurface::ConstPointer osfSurface, OutputMeshPointer mesh); 96 | virtual void CopyInputOSFSurfaceToOutputMeshCells(typename InputOSFGraphType::OSFSurface::ConstPointer osfSurface, OutputMeshPointer mesh); 97 | 98 | SurfaceType m_SurfaceType; 99 | 100 | private: 101 | }; 102 | 103 | } // end namespace itk 104 | 105 | #ifndef ITK_MANUAL_INSTANTIATION 106 | #include "itkOSFGraphToMeshFilter.txx" 107 | #endif 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkCenterNormalColumnBuilderFilter.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkCenterNormalColumnBuilderFilter_h 19 | #define _itkCenterNormalColumnBuilderFilter_h 20 | 21 | #include "itkOSFGraphToOSFGraphFilter.h" 22 | 23 | namespace itk 24 | { 25 | /**\class CenterNormalColumnBuilderFilter 26 | * \brief Builds the columns in the graph based on the vertex points of the existing graph. 27 | * \date 12/9/2014 28 | * \author Christian Bauer, Markus Van Tol 29 | * Builds the columns in the graph based on the vertex points of the existing graph. CONTINUE 30 | * Template parameters for class CenterNormalColumnBuilderFilter: 31 | * 32 | * - TInputOSFGraph = The graph type of the input to build columns for. 33 | * - TOutputOSFGraph = The graph type of the input with built columns. 34 | */ 35 | template 36 | class ITK_EXPORT CenterNormalColumnBuilderFilter : public OSFGraphToOSFGraphFilter 37 | { 38 | public: 39 | using Self = CenterNormalColumnBuilderFilter; 40 | using Superclass = OSFGraphToOSFGraphFilter; 41 | using Pointer = SmartPointer< Self >; 42 | using ConstPointer = SmartPointer< const Self >; 43 | 44 | ITK_DISALLOW_COPY_AND_ASSIGN(CenterNormalColumnBuilderFilter); 45 | 46 | itkNewMacro( Self ); 47 | itkTypeMacro( CenterNormalColumnBuilderFilter, OSFGraphToOSFGraphFilter ); 48 | 49 | using InputOSFGraphType = TInputOSFGraph; 50 | using InputOSFGraphConstPointer = typename InputOSFGraphType::ConstPointer; 51 | 52 | using OutputOSFGraphType = TOutputOSFGraph; 53 | using OutputOSFGraphPointer = typename OutputOSFGraphType::Pointer; 54 | 55 | itkSetMacro( StepLength, float ); 56 | itkGetMacro( StepLength, float ); 57 | 58 | itkSetMacro( NumberOfSteps, unsigned int ); 59 | itkGetMacro( NumberOfSteps, unsigned int ); 60 | 61 | itkSetVectorMacro( CenterPoint, float, 3 ); 62 | itkGetVectorMacro( CenterPoint, const float, 3 ); 63 | 64 | protected: 65 | /** Constructor for use by New() method. */ 66 | CenterNormalColumnBuilderFilter() = default; 67 | ~CenterNormalColumnBuilderFilter() override = default; 68 | void PrintSelf(std::ostream& os, Indent indent) const override; 69 | 70 | void GenerateData() override; 71 | 72 | float m_StepLength{ 0 }; 73 | unsigned int m_NumberOfSteps{ 0 }; 74 | 75 | using OSFSurface = typename OutputOSFGraphType::OSFSurface; 76 | using VertexIdentifier = typename OSFSurface::VertexIdentifier; 77 | using CellIdentifier = typename OSFSurface::CellIdentifier; 78 | virtual void BuildColumn(VertexIdentifier vertexId); 79 | 80 | //typedef Vector< float, ::itk::GetImageDimension::ImageDimension > CenterPoint; 81 | float m_CenterPoint[3]; // todo: assuming fixed number of dimensions here 82 | //typedef Vector< float, ::itk::GetImageDimension::ImageDimension > DirectionVector; 83 | using DirectionVector = Vector< float, 3 >; // todo: assuming fixed number of dimensions here 84 | virtual DirectionVector GetNormal(const VertexIdentifier vertexId) const; 85 | 86 | std::vector< std::set > m_VertexToCellLookupTable; 87 | virtual void BuildVertexToCellLookupTable(); 88 | 89 | private: 90 | 91 | }; // end class CenterNormalColumnBuilderFilter 92 | 93 | } // end namespace itk 94 | 95 | #ifndef ITK_MANUAL_INSTANTIATION 96 | #include "itkCenterNormalColumnBuilderFilter.txx" 97 | #endif 98 | 99 | #endif 100 | 101 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkSimpleOSFGraphBuilderFilter.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkSimpleOSFGraphBuilderFilter_h 19 | #define _itkSimpleOSFGraphBuilderFilter_h 20 | 21 | #include "itkOSFGraphToOSFGraphFilter.h" 22 | 23 | namespace itk 24 | { 25 | /**\class SimpleOSFGraphBuilderFilter 26 | * \brief Generates the solvable graph information for an OSF graph object. 27 | * \date 12/9/2014 28 | * \author Christian Bauer 29 | * Given an OSF graph with the costs and locations of the nodes and columns, this builds an accompanying 30 | * maximum-flow-solvable graph type, with the source and sink nodes in order to generate the solution to 31 | * the surface. \n 32 | * This also applies the hard and soft smoothness requirements. 33 | * Template parameters for class SimpleOSFGraphBuilderFilter: 34 | * 35 | * - TInputOSFGraph = The graph type of the input. 36 | * - TOutputOSFGraph = The graph type of the output. 37 | */ 38 | template 39 | class ITK_EXPORT SimpleOSFGraphBuilderFilter : public OSFGraphToOSFGraphFilter 40 | { 41 | public: 42 | using Self = SimpleOSFGraphBuilderFilter; 43 | using Superclass = OSFGraphToOSFGraphFilter; 44 | using Pointer = SmartPointer< Self >; 45 | using ConstPointer = SmartPointer< const Self >; 46 | 47 | ITK_DISALLOW_COPY_AND_ASSIGN(SimpleOSFGraphBuilderFilter); 48 | 49 | itkNewMacro( Self ); 50 | itkTypeMacro( SimpleOSFGraphBuilderFilter, OSFGraphToOSFGraphFilter ); 51 | 52 | using InputOSFGraphType = TInputOSFGraph; 53 | using InputOSFGraphConstPointer = typename InputOSFGraphType::ConstPointer; 54 | 55 | using OutputOSFGraphType = TOutputOSFGraph; 56 | using OutputOSFGraphPointer = typename OutputOSFGraphType::Pointer; 57 | 58 | itkSetMacro( SmoothnessConstraint, unsigned int ); 59 | itkGetMacro( SmoothnessConstraint, unsigned int ); 60 | 61 | itkSetMacro( SoftSmoothnessPenalty, double ); 62 | itkGetMacro( SoftSmoothnessPenalty, double ); 63 | 64 | protected: 65 | /** Constructor for use by New() method. */ 66 | SimpleOSFGraphBuilderFilter() = default; 67 | ~SimpleOSFGraphBuilderFilter() override = default; 68 | void PrintSelf(std::ostream& os, Indent indent) const override; 69 | 70 | void GenerateData() override; 71 | 72 | using SurfaceIdentifier = typename OutputOSFGraphType::VertexIdentifier; 73 | using OSFSurface = typename OutputOSFGraphType::OSFSurface; 74 | using VertexIdentifier = typename OSFSurface::VertexIdentifier; 75 | virtual void CreateNodesForColumn(SurfaceIdentifier surfaceId, VertexIdentifier vertexId); 76 | virtual void CreateIntraColumnArcsForColumn(SurfaceIdentifier surfaceId, VertexIdentifier vertexId); 77 | virtual void CreateInterColumnArcsForColumn(SurfaceIdentifier surfaceId, VertexIdentifier vertexId); 78 | 79 | // note: shanhui said that some people say the value has to be a large negative number 80 | // but he did not experience any negative effects 81 | // this behavior may probably depend on the range of the actual cost values 82 | const typename OutputOSFGraphType::GraphCosts m_Infinity{ std::numeric_limits::infinity() }; 83 | const typename OutputOSFGraphType::GraphCosts m_ColumnBasedNodeWeight{ -1 }; 84 | 85 | unsigned int m_SmoothnessConstraint{ itk::NumericTraits::max() }; 86 | double m_SoftSmoothnessPenalty{ 0 }; 87 | 88 | private: 89 | }; // end class SimpleOSFGraphBuilderFilter 90 | 91 | } // end namespace itk 92 | 93 | #ifndef ITK_MANUAL_INSTANTIATION 94 | #include "itkSimpleOSFGraphBuilderFilter.txx" 95 | #endif 96 | 97 | #endif 98 | 99 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkOSFGraphSource.txx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkOSFGraphSource_txx 19 | #define _itkOSFGraphSource_txx 20 | 21 | #include "itkOSFGraph.h" 22 | 23 | namespace itk 24 | { 25 | 26 | //---------------------------------------------------------------------------- 27 | template 28 | OSFGraphSource 29 | ::OSFGraphSource() 30 | { 31 | // Create the output. We use static_cast<> here because we know the default 32 | // output must be of type TOutputMesh 33 | OutputOSFGraphPointer output 34 | = static_cast(this->MakeOutput(0).GetPointer()); 35 | 36 | this->ProcessObject::SetNumberOfRequiredOutputs(1); 37 | this->ProcessObject::SetNthOutput( 0, output.GetPointer() ); 38 | } 39 | 40 | //---------------------------------------------------------------------------- 41 | template 42 | typename OSFGraphSource::DataObjectPointer 43 | OSFGraphSource 44 | ::MakeOutput(DataObjectPointerArraySizeType) 45 | { 46 | return static_cast(TOutputOSFGraph::New().GetPointer()); 47 | } 48 | 49 | //---------------------------------------------------------------------------- 50 | template 51 | typename OSFGraphSource::OutputOSFGraphType* 52 | OSFGraphSource 53 | ::GetOutput(void) 54 | { 55 | if (this->GetNumberOfOutputs() < 1) 56 | { 57 | return 0; 58 | } 59 | 60 | return static_cast 61 | (this->ProcessObject::GetOutput(0)); 62 | } 63 | 64 | //---------------------------------------------------------------------------- 65 | template 66 | typename OSFGraphSource::OutputOSFGraphType* 67 | OSFGraphSource 68 | ::GetOutput(unsigned int idx) 69 | { 70 | return static_cast 71 | (this->ProcessObject::GetOutput(idx)); 72 | } 73 | 74 | //---------------------------------------------------------------------------- 75 | template 76 | void 77 | OSFGraphSource 78 | ::GenerateInputRequestedRegion() 79 | { 80 | Superclass::GenerateInputRequestedRegion(); 81 | } 82 | 83 | //---------------------------------------------------------------------------- 84 | template 85 | void 86 | OSFGraphSource 87 | ::GraftOutput(DataObject *graft) 88 | { 89 | this->GraftNthOutput(0, graft); 90 | } 91 | 92 | //---------------------------------------------------------------------------- 93 | template 94 | void 95 | OSFGraphSource 96 | ::GraftNthOutput(unsigned int idx, DataObject *graft) 97 | { 98 | if ( idx >= this->GetNumberOfOutputs() ) 99 | { 100 | itkExceptionMacro(<<"Requested to graft output " << idx << 101 | " but this filter only has " << this->GetNumberOfOutputs() << " Outputs."); 102 | } 103 | 104 | if ( !graft ) 105 | { 106 | itkExceptionMacro(<<"Requested to graft output that is a nullptr pointer" ); 107 | } 108 | 109 | DataObject * output = this->GetOutput( idx ); 110 | 111 | // Call Graft on the OSFGraph in order to copy meta-information, and containers. 112 | // todo: OSFGraph needs support for that!!! 113 | output->Graft( graft ); 114 | } 115 | 116 | //---------------------------------------------------------------------------- 117 | template 118 | void 119 | OSFGraphSource 120 | ::PrintSelf(std::ostream& os, Indent indent) const 121 | { 122 | Superclass::PrintSelf(os,indent); 123 | // todo: implement 124 | } 125 | 126 | } // namespace 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkSealingSegmentationMergerImageFilter.txx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef __itkSealingSegmentationMergerImageFilter_txx 19 | #define __itkSealingSegmentationMergerImageFilter_txx 20 | 21 | #include "itkSealingSegmentationMergerImageFilter.h" 22 | #include "itkImageRegionIterator.h" 23 | #include "itkImageRegionConstIterator.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define X_AXIS 0 31 | #define Y_AXIS 1 32 | #define Z_AXIS 2 33 | 34 | namespace itk 35 | { 36 | 37 | template 38 | void 39 | SealingSegmentationMergerImageFilter 40 | ::BeforeThreadedGenerateData() 41 | { 42 | // create output image 43 | const auto& input = this->GetInput(); 44 | auto output = this->GetOutput(); 45 | output->CopyInformation(input); 46 | output->Allocate(); 47 | } 48 | 49 | template 50 | void 51 | SealingSegmentationMergerImageFilter 52 | ::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread) 53 | { 54 | using InputNeighborhoodIteratorType = itk::ConstNeighborhoodIterator; 55 | using UptakeIteratorType = itk::ImageRegionIterator; 56 | using OutputIteratorType = itk::ImageRegionIterator; 57 | 58 | using InputRadiusType = typename InputNeighborhoodIteratorType::RadiusType; 59 | InputRadiusType radius; 60 | radius.Fill(1); 61 | 62 | InputNeighborhoodIteratorType inputIt(radius, this->GetInput(), outputRegionForThread); //iterator for newly created label 63 | InputNeighborhoodIteratorType segmentationIt(radius, this->GetLabelImage(), outputRegionForThread); //iterator for existing labels 64 | UptakeIteratorType uptakeIt(this->GetDataImage(), outputRegionForThread); 65 | OutputIteratorType outputIt(this->GetOutput(), outputRegionForThread); 66 | while (!outputIt.IsAtEnd()) //Zero out any data left over from old memory 67 | { 68 | outputIt.Set(0); 69 | ++outputIt; 70 | } 71 | outputIt.GoToBegin(); 72 | while (!inputIt.IsAtEnd()) //Apply the existing labels and the actual sealing 73 | { 74 | if (inputIt.GetCenterPixel()>0 && (segmentationIt.GetCenterPixel()==0 || m_PaintOver)) //If the new label is to be applied and either the existing one is blank or set to be painted over, then apply the new label 75 | outputIt.Set(m_Label); 76 | else if (segmentationIt.GetCenterPixel()>0) //Otherwise, if there's an existing label, apply it 77 | outputIt.Set(segmentationIt.GetCenterPixel()); 78 | else if (m_Sealing && (uptakeIt.Get()>=m_Threshold || m_NecroticRegion)) //Otherwise, if sealing's active and the voxel is either above the threshold or the region is marked necrotic, thereby ignoring the threshold, then check if the voxel must be sealed 79 | { 80 | for (int dim=0; dim<3; ++dim) //check each dimension 81 | { 82 | if (inputIt.GetPrevious(dim)>0 && (segmentationIt.GetNext(dim)>0 || inputIt.GetNext(dim)>0)) //If previous in this dimension is a new label and next is a new or old label, seal with new label 83 | outputIt.Set(m_Label); 84 | else if (inputIt.GetNext(dim)>0 && (segmentationIt.GetPrevious(dim)>0 || inputIt.GetPrevious(dim)>0)) //If next in this dimension is a new label and previous is a new or old label, seal with new label 85 | outputIt.Set(m_Label); 86 | } 87 | } 88 | else 89 | outputIt.Set(0); 90 | 91 | ++inputIt; 92 | ++segmentationIt; 93 | ++uptakeIt; 94 | ++outputIt; 95 | } 96 | } 97 | 98 | template 99 | void SealingSegmentationMergerImageFilter:: 100 | PrintSelf(std::ostream& os, Indent indent) const 101 | { 102 | Superclass::PrintSelf(os,indent); 103 | } 104 | 105 | } // end namespace itk 106 | 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /PETTumorSegmentation/qSlicerPETTumorSegmentationModule.cxx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | Portions (c) Copyright University of Iowa All Rights Reserved. 6 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved. 7 | 8 | See COPYRIGHT.txt 9 | or http://www.slicer.org/copyright/copyright.txt for details. 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | ==============================================================================*/ 18 | 19 | // Qt includes 20 | #include 21 | 22 | // PETTumorSegmentation Logic includes 23 | #include 24 | 25 | // PETTumorSegmentation includes 26 | #include "qSlicerPETTumorSegmentationModule.h" 27 | 28 | //----------------------------------------------------------------------------- 29 | #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) 30 | #include 31 | Q_EXPORT_PLUGIN2(qSlicerPETTumorSegmentationModule, qSlicerPETTumorSegmentationModule); 32 | #endif 33 | 34 | //----------------------------------------------------------------------------- 35 | /// \ingroup Slicer_QtModules_ExtensionTemplate 36 | class qSlicerPETTumorSegmentationModulePrivate 37 | { 38 | public: 39 | qSlicerPETTumorSegmentationModulePrivate(); 40 | }; 41 | 42 | //----------------------------------------------------------------------------- 43 | // qSlicerPETTumorSegmentationModulePrivate methods 44 | 45 | //----------------------------------------------------------------------------- 46 | qSlicerPETTumorSegmentationModulePrivate::qSlicerPETTumorSegmentationModulePrivate() = default; 47 | 48 | //----------------------------------------------------------------------------- 49 | // qSlicerPETTumorSegmentationModule methods 50 | 51 | //----------------------------------------------------------------------------- 52 | qSlicerPETTumorSegmentationModule::qSlicerPETTumorSegmentationModule(QObject* _parent) 53 | : Superclass(_parent) 54 | , d_ptr(new qSlicerPETTumorSegmentationModulePrivate) 55 | { 56 | } 57 | 58 | //----------------------------------------------------------------------------- 59 | qSlicerPETTumorSegmentationModule::~qSlicerPETTumorSegmentationModule() = default; 60 | 61 | //----------------------------------------------------------------------------- 62 | QString qSlicerPETTumorSegmentationModule::helpText() const 63 | { 64 | return "This is a loadable module for tumor and lymph node segmentation in PET scans."; 65 | } 66 | 67 | //----------------------------------------------------------------------------- 68 | QString qSlicerPETTumorSegmentationModule::acknowledgementText() const 69 | { 70 | return "This work was funded by NIH grants U01CA140206 and U24CA180918."; 71 | } 72 | 73 | //----------------------------------------------------------------------------- 74 | QStringList qSlicerPETTumorSegmentationModule::contributors() const 75 | { 76 | QStringList moduleContributors; 77 | moduleContributors << QString("Christian Bauer (University of Iowa)"); 78 | moduleContributors << QString("Markus van Tol (University of Iowa)"); 79 | return moduleContributors; 80 | } 81 | 82 | //----------------------------------------------------------------------------- 83 | QIcon qSlicerPETTumorSegmentationModule::icon() const 84 | { 85 | return QIcon(":/Icons/PETTumorSegmentation.png"); 86 | } 87 | 88 | //----------------------------------------------------------------------------- 89 | QStringList qSlicerPETTumorSegmentationModule::categories() const 90 | { 91 | return QStringList() << "EditorEffect"; 92 | } 93 | 94 | //----------------------------------------------------------------------------- 95 | QStringList qSlicerPETTumorSegmentationModule::dependencies() const 96 | { 97 | return QStringList(); 98 | } 99 | 100 | //----------------------------------------------------------------------------- 101 | void qSlicerPETTumorSegmentationModule::setup() 102 | { 103 | this->Superclass::setup(); 104 | } 105 | 106 | //----------------------------------------------------------------------------- 107 | bool qSlicerPETTumorSegmentationModule::isHidden() const 108 | { 109 | return true; 110 | } 111 | 112 | //----------------------------------------------------------------------------- 113 | qSlicerAbstractModuleRepresentation* qSlicerPETTumorSegmentationModule 114 | ::createWidgetRepresentation() 115 | { 116 | return 0; 117 | } 118 | 119 | //----------------------------------------------------------------------------- 120 | vtkMRMLAbstractLogic* qSlicerPETTumorSegmentationModule::createLogic() 121 | { 122 | return vtkSlicerPETTumorSegmentationLogic::New(); 123 | } 124 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkSealingSegmentationMergerImageFilter.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef __itkSealingSegmentationMergerImageFilter_h 19 | #define __itkSealingSegmentationMergerImageFilter_h 20 | 21 | #include "itkLinearInterpolateImageFunction.h" 22 | #include "itkNearestNeighborInterpolateImageFunction.h" 23 | #include "itkInterpolateImageFunction.h" 24 | #include "itkConceptChecking.h" 25 | #include "itkImageToImageFilter.h" 26 | #include "itkBinaryThresholdImageFilter.h" 27 | #include "itkConnectedComponentImageFilter.h" 28 | #include "itkVotingBinaryIterativeHoleFillingImageFilter.h" 29 | #include "itkSliceBySliceImageFilter.h" 30 | #include "itkGrayscaleFillholeImageFilter.h" 31 | 32 | namespace itk 33 | { 34 | /**\class SealingSegmentationMergerImageFilter 35 | * \brief Merges two segmentation volumes together, with one explicitly of a new object. 36 | * \date 12/9/2014 37 | * \author Christian Bauer, Markus Van Tol 38 | * Merges a new object segmentation with the segmentation of other objects. If set, avoids overwriting 39 | * old objects and seals gaps between the new object and old objects or more of the new object. 40 | * Template parameters for class SealingSegmentationMergerImageFilter: 41 | * 42 | * - TInputImage = The image type of the new segmentation to be incorporated. 43 | * - TUptakeImage = The image type of the existing segmentation to be added to. 44 | * - TOutputImage = The image type of the merged output. 45 | */ 46 | template 47 | class ITK_EXPORT SealingSegmentationMergerImageFilter : public ImageToImageFilter 48 | { 49 | public: 50 | /** Standard class type aliases. */ 51 | using Self = SealingSegmentationMergerImageFilter; 52 | using Superclass = ImageToImageFilter; 53 | using Pointer = SmartPointer; 54 | using ConstPointer = SmartPointer; 55 | 56 | ITK_DISALLOW_COPY_AND_ASSIGN(SealingSegmentationMergerImageFilter); 57 | 58 | /** Method for creation through the object factory. */ 59 | itkNewMacro(Self); 60 | 61 | /** Run-time type information (and related methods). */ 62 | itkTypeMacro(SealingSegmentationMergerImageFilter, ImageToImageFilter); 63 | 64 | /** Some convenient type aliases. */ 65 | using InputImageType = TInputImage; 66 | using InputImagePointer = typename InputImageType::ConstPointer; 67 | using InputImageRegionType = typename InputImageType::RegionType; 68 | using InputImagePixelType = typename InputImageType::PixelType; 69 | 70 | using UptakeImageType = TUptakeImage; 71 | using UptakeImagePointer = typename UptakeImageType::Pointer; 72 | using UptakeImageRegionType = typename UptakeImageType::RegionType; 73 | using UptakeImagePixelType = typename UptakeImageType::PixelType; 74 | 75 | using OutputImageType = TOutputImage; 76 | using OutputImagePointer = typename OutputImageType::Pointer; 77 | using OutputImageRegionType = typename OutputImageType::RegionType; 78 | using OutputImagePixelType = typename OutputImageType::PixelType; 79 | 80 | using PointType = typename TOutputImage::PointType ; 81 | 82 | /** ImageDimension enumeration */ 83 | static constexpr unsigned int InputImageDimension = TInputImage::ImageDimension; 84 | static constexpr unsigned int OutputImageDimension = TOutputImage::ImageDimension; 85 | 86 | itkSetObjectMacro(DataImage, UptakeImageType); 87 | itkGetObjectMacro(DataImage, UptakeImageType); 88 | 89 | itkSetObjectMacro(LabelImage, InputImageType); 90 | itkGetObjectMacro(LabelImage, InputImageType); 91 | 92 | itkSetMacro(Threshold, UptakeImagePixelType); 93 | itkGetMacro(Threshold, UptakeImagePixelType); 94 | 95 | itkSetMacro(Label, InputImagePixelType); 96 | itkGetMacro(Label, InputImagePixelType); 97 | 98 | itkSetMacro(PaintOver, bool); 99 | itkGetMacro(PaintOver, bool); 100 | 101 | itkSetMacro(Sealing, bool); 102 | itkGetMacro(Sealing, bool); 103 | 104 | itkSetMacro(NecroticRegion, bool); 105 | itkGetMacro(NecroticRegion, bool); 106 | 107 | #ifdef ITK_USE_CONCEPT_CHECKING 108 | /** Begin concept checking */ 109 | itkConceptMacro(ImageDimensionCheck, 110 | (Concept::SameDimensionOrMinusOne)); 112 | /** End concept checking */ 113 | #endif 114 | 115 | protected: 116 | SealingSegmentationMergerImageFilter() = default; 117 | ~SealingSegmentationMergerImageFilter() override = default; 118 | void PrintSelf(std::ostream& os, Indent indent) const override; 119 | 120 | void BeforeThreadedGenerateData() override; 121 | void DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread) override; 122 | 123 | private: 124 | UptakeImagePixelType m_Threshold{ 0.0 }; 125 | InputImagePixelType m_Label{ 1 } ; 126 | bool m_Sealing{ false }; 127 | bool m_PaintOver{ false }; 128 | bool m_NecroticRegion{ false }; 129 | typename InputImageType::Pointer m_LabelImage; 130 | typename UptakeImageType::Pointer m_DataImage; 131 | }; 132 | 133 | } // end namespace itk 134 | 135 | #ifndef ITK_MANUAL_INSTANTIATION 136 | #include "itkSealingSegmentationMergerImageFilter.txx" 137 | #endif 138 | 139 | #endif 140 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkLOGISMOSOSFGraphSolverFilter.txx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkLOGISMOSOSFGraphSolverFilter_txx 19 | #define _itkLOGISMOSOSFGraphSolverFilter_txx 20 | 21 | #include "itkLOGISMOSOSFGraphSolverFilter.h" 22 | 23 | namespace itk 24 | { 25 | 26 | //---------------------------------------------------------------------------- 27 | template 28 | LOGISMOSOSFGraphSolverFilter 29 | ::~LOGISMOSOSFGraphSolverFilter() 30 | { 31 | if (m_MaxFlowGraph!=nullptr) 32 | { 33 | delete m_MaxFlowGraph; 34 | m_MaxFlowGraph = nullptr; 35 | } 36 | } 37 | 38 | //---------------------------------------------------------------------------- 39 | template 40 | void 41 | LOGISMOSOSFGraphSolverFilter 42 | ::GenerateData() 43 | { 44 | this->CopyInputOSFGraphToOutputOSFGraphSurfaces(); 45 | this->CopyInputOSFGraphToOutputOSFGraphGraph(); 46 | InputOSFGraphConstPointer input = this->GetInput(); 47 | // build graph 48 | m_MaxFlowGraph = new MaxFlowGraphType(); 49 | 50 | this->BuildMaxFlowGraphGraph(); 51 | // solve max flow 52 | m_FlowValue = m_MaxFlowGraph->solve(); 53 | 54 | // store result 55 | this->UpdateResult(); 56 | delete m_MaxFlowGraph; 57 | m_MaxFlowGraph = nullptr; 58 | } 59 | 60 | //---------------------------------------------------------------------------- 61 | template 62 | void 63 | LOGISMOSOSFGraphSolverFilter 64 | ::BuildMaxFlowGraphGraph() 65 | { 66 | // add nodes with terminal weights 67 | using GraphNodeContainer = typename InputOSFGraphType::GraphNodesContainer; 68 | typename GraphNodeContainer::ConstPointer graphNodes = this->GetInput()->GetNodes(); 69 | typename GraphNodeContainer::ConstIterator graphNodesItr = graphNodes->Begin(); 70 | typename GraphNodeContainer::ConstIterator graphNodesEnd = graphNodes->End(); 71 | 72 | m_MaxFlowGraph->add_nodes( graphNodes->Size() ); 73 | 74 | while ( graphNodesItr!=graphNodesEnd ) 75 | { 76 | typename InputOSFGraphType::GraphNodeIdentifier nodeId = graphNodesItr.Index(); 77 | const typename InputOSFGraphType::GraphNode& node = graphNodesItr.Value(); 78 | m_MaxFlowGraph->add_st_edge( nodeId, node.cap_source, node.cap_sink ); 79 | ++graphNodesItr; 80 | } 81 | 82 | // add edges 83 | using GraphEdgesContainer = typename InputOSFGraphType::GraphEdgesContainer; 84 | typename GraphEdgesContainer::ConstPointer graphEdges = this->GetInput()->GetEdges(); 85 | typename GraphEdgesContainer::ConstIterator graphEdgesItr = graphEdges->Begin(); 86 | typename GraphEdgesContainer::ConstIterator graphEdgesEnd = graphEdges->End(); 87 | while ( graphEdgesItr!=graphEdgesEnd ) 88 | { 89 | const typename InputOSFGraphType::GraphEdge& edge = graphEdgesItr.Value(); 90 | m_MaxFlowGraph->add_edge( edge.startNodeId, edge.endNodeId, edge.cap, edge.rev_cap ); 91 | ++graphEdgesItr; 92 | } 93 | 94 | } 95 | 96 | //---------------------------------------------------------------------------- 97 | template 98 | void 99 | LOGISMOSOSFGraphSolverFilter 100 | ::UpdateResult() 101 | { 102 | // note: we assume Boykov's max flow lib procudes the same node_id's we use 103 | 104 | // note: instead of iterating through all nodes, we could do a binary search on the nodes associated with a column 105 | // this could give some speedup in case of many column positions 106 | 107 | if (m_MaxFlowGraph==nullptr) 108 | return; 109 | 110 | InputOSFGraphConstPointer input = this->GetInput(); 111 | OutputOSFGraphPointer output = this->GetOutput(); 112 | 113 | // set all column positions to 0 first 114 | for (typename OutputOSFGraphType::SurfaceIdentifier surfaceId=0; surfaceIdGetNumberOfSurfaces(); surfaceId++) 115 | { 116 | typename OutputOSFGraphType::OSFSurfacePointer surface = output->GetSurface(surfaceId); 117 | for (typename OutputOSFGraphType::VertexIdentifier vertexId=0; vertexIdGetNumberOfVertices(); vertexId++) 118 | surface->SetCurrentVertexPositionIdentifier(vertexId,0); 119 | } 120 | 121 | // update to higest column position still attached to the source 122 | std::size_t numNodes = m_MaxFlowGraph->get_node_cnt(); 123 | for (std::size_t nodeId=0; nodeIdin_source_set(nodeId)) 126 | { 127 | // update mesh position 128 | const typename InputOSFGraphType::GraphNode& node = input->GetNode( nodeId ); 129 | typename OutputOSFGraphType::OSFSurfacePointer surface = output->GetSurface(node.surfaceId); 130 | typename OutputOSFGraphType::ColumnPositionIdentifier currentColumnPosition = surface->GetCurrentVertexPositionIdentifier(node.vertexId); 131 | if (node.positionId>currentColumnPosition) 132 | surface->SetCurrentVertexPositionIdentifier(node.vertexId, node.positionId); 133 | } 134 | } 135 | 136 | } 137 | 138 | //---------------------------------------------------------------------------- 139 | template 140 | void 141 | LOGISMOSOSFGraphSolverFilter 142 | ::PrintSelf(std::ostream& os, Indent indent) const 143 | { 144 | Superclass::PrintSelf(os,indent); 145 | // todo: implement 146 | } 147 | 148 | } // namespace 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkWorkers.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | #ifndef _itkWorkers_h 18 | #define _itkWorkers_h 19 | 20 | #include 21 | 22 | namespace itk 23 | { 24 | // TODO: write class description with usage examples 25 | /**\class Workers 26 | * \brief Runs functions in a multithreaded manner. 27 | * \date 12/9/2014 28 | * \author Christian Bauer 29 | * Runs functions in a multithreaded manner. CONTINUE 30 | */ 31 | class Workers 32 | { 33 | public: 34 | Workers(int numWorkers=1024); 35 | 36 | int GetNumberOfWorkers() const; 37 | 38 | // run non-const method on object without parameters 39 | template 40 | void RunMethod(T* object, void(T::*method)(int, int) ); 41 | 42 | // run non-const method on object with one parameter 43 | template 44 | void RunMethod(T* object, void(T::*method)(int, int, T1), T1 p1 ); 45 | 46 | // run const method on object without parameters 47 | template 48 | void RunMethod(T* object, void(T::*method)(int, int) const ); 49 | 50 | // run static method or function without parameters 51 | void RunFunction(void(*function)(int, int)); 52 | 53 | // run static method or function with one parameter 54 | template 55 | void RunFunction(void(*function)(int, int, T1), T1 p1); 56 | 57 | // run non-const method on object without parameters for a specified range of values 58 | template 59 | void RunMethodForRange(T* object, void(T::*method)(RangeType), RangeType min, RangeType max ); 60 | 61 | // run non-const method on object with one parameter for a specified range of values 62 | template 63 | void RunMethodForRange(T* object, void(T::*method)(RangeType, T1), RangeType min, RangeType max, T1 p1 ); 64 | 65 | // run static method or function without parameters for a specified range of values 66 | template 67 | void RunFunctionForRange(void(*function)(RangeType), RangeType min, RangeType max); 68 | 69 | // run static method or function with one parameter for a specified range of values 70 | template 71 | void RunFunctionForRange(void(*function)(RangeType, T1), RangeType min, RangeType max, T1 p1); 72 | 73 | // run static method or function with two parameter for a specified range of values 74 | // TODO: implement 75 | 76 | // run static method or function with three parameter for a specified range of values 77 | template 78 | void RunFunctionForRange(void(*function)(RangeType, T1, T2, T3), RangeType min, RangeType max, T1 p1, T2 p2, T3 p3); 79 | 80 | // run static method or function with five parameter for a specified range of values 81 | template 82 | void RunFunctionForRange(void(*function)(RangeType, T1, T2, T3, T4, T5), RangeType min, RangeType max, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5); 83 | 84 | // run static method or function with six parameter for a specified range of values 85 | template 86 | void RunFunctionForRange(void(*function)(RangeType, T1, T2, T3, T4, T5, T6), RangeType min, RangeType max, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6); 87 | 88 | protected: 89 | int m_NumWorkers; 90 | using MultiThreader = itk::PlatformMultiThreader; 91 | typename MultiThreader::Pointer m_MultiThreader; 92 | 93 | // callback to run non-const method on object without parameters 94 | template 95 | static ITK_THREAD_RETURN_TYPE RunMethodCB(void* arg); 96 | 97 | // callback to run non-const method on object with one parameter 98 | template 99 | static ITK_THREAD_RETURN_TYPE RunMethodCB(void* arg); 100 | 101 | // callback to run const method on object without parameters 102 | template 103 | static ITK_THREAD_RETURN_TYPE RunConstMethodCB(void* arg); 104 | 105 | // callback to run static method or function without parameters 106 | static ITK_THREAD_RETURN_TYPE RunFunctionCB(void* arg); 107 | 108 | // callback to run static method or function with one parameter 109 | template 110 | static ITK_THREAD_RETURN_TYPE RunFunctionCB(void* arg); 111 | 112 | // callback to run method without parameters for a specified range of values 113 | template 114 | static ITK_THREAD_RETURN_TYPE RunMethodForRangeCB(void* arg); 115 | 116 | // callback to run method with one parameter for a specified range of values 117 | template 118 | static ITK_THREAD_RETURN_TYPE RunMethodForRangeCB(void* arg); 119 | 120 | // callback to run static method or function without parameters for a specified range of values 121 | template 122 | static ITK_THREAD_RETURN_TYPE RunFunctionForRangeCB(void* arg); 123 | 124 | // callback to run static method or function with one parameters for a specified range of values 125 | template 126 | static ITK_THREAD_RETURN_TYPE RunFunctionForRangeCB(void* arg); 127 | 128 | // callback to run static method or function with two parameters for a specified range of values 129 | // TODO: implement 130 | 131 | // callback to run static method or function with three parameters for a specified range of values 132 | template 133 | static ITK_THREAD_RETURN_TYPE RunFunctionForRangeCB(void* arg); 134 | 135 | // callback to run static method or function with five parameters for a specified range of values 136 | template 137 | static ITK_THREAD_RETURN_TYPE RunFunctionForRangeCB(void* arg); 138 | 139 | // callback to run static method or function with six parameters for a specified range of values 140 | template 141 | static ITK_THREAD_RETURN_TYPE RunFunctionForRangeCB(void* arg); 142 | }; 143 | 144 | } // end namespace itk 145 | 146 | #ifndef ITK_MANUAL_INSTANTIATION 147 | #include "itkWorkers.txx" 148 | #endif 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkOSFSurface.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkOSFSurface_h 19 | #define _itkOSFSurface_h 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | namespace itk 26 | { 27 | /**\class OSFSurface 28 | * \brief 29 | * \date 12/9/2014 30 | * \author Christian Bauer 31 | * ? 32 | * Template parameters for class OSFSurface: 33 | * 34 | * - TCostType = ? 35 | * - TSurfaceMeshTraits = ? 36 | */ 37 | 38 | template > 39 | class ITK_EXPORT OSFSurface : public Object // todo: should probably change to DataObject 40 | { 41 | public: 42 | using Self = OSFSurface; 43 | using Superclass = Object; 44 | using Pointer = SmartPointer< Self >; 45 | using ConstPointer = SmartPointer< const Self >; 46 | 47 | ITK_DISALLOW_COPY_AND_ASSIGN(OSFSurface); 48 | 49 | itkNewMacro(Self); 50 | itkTypeMacro(OSFSurface, Object); 51 | 52 | // utility type alias that helps defining cells and coordinates 53 | using MeshTraits = TSurfaceMeshTraits; 54 | 55 | // type aliases for identifiers 56 | using IdentifierType = unsigned long; 57 | using VertexIdentifier = IdentifierType; 58 | using ColumnPositionIdentifier = IdentifierType; 59 | using CellIdentifier = IdentifierType; 60 | 61 | // type aliases for a column of an OSF surface 62 | using CoordRepType= typename MeshTraits::CoordRepType; 63 | static constexpr unsigned int PointDimension = MeshTraits::PointDimension; 64 | using CoordinateType = typename MeshTraits::PointType; 65 | using ColumnCoordinatesContainer = VectorContainer< ColumnPositionIdentifier, CoordinateType >; 66 | using ColumnCostType = TCostType; 67 | using ColumnCostsContainer = VectorContainer< ColumnPositionIdentifier, ColumnCostType >; 68 | 69 | // type aliases for a vertex of an OSF surface (not a coordinate, but a whole column) 70 | using VertexColumnCoordinatesContainer = VectorContainer< VertexIdentifier, typename ColumnCoordinatesContainer::Pointer >; 71 | using VertexColumnCostsContainer = VectorContainer< VertexIdentifier, typename ColumnCostsContainer::Pointer >; 72 | using VertexPositionIdentifierContainer = VectorContainer< VertexIdentifier, ColumnPositionIdentifier >; 73 | 74 | // type aliases for a cell of an OSF surface 75 | using CellTraits= typename MeshTraits::CellTraits ; 76 | using CellPixelType = typename MeshTraits::CellPixelType; 77 | using CellType = CellInterface< CellPixelType, CellTraits >; 78 | using CellRawPointer = typename CellType::CellRawPointer; 79 | using CellAutoPointer = typename CellType::CellAutoPointer; 80 | using CellsContainer = typename MeshTraits::CellsContainer; 81 | 82 | VertexIdentifier GetNumberOfVertices( ) const; 83 | ColumnPositionIdentifier GetNumberOfColumns(VertexIdentifier vertexId) const; 84 | 85 | // access to column coordinates of a vertex 86 | ColumnCoordinatesContainer* GetColumnCoordinates(VertexIdentifier vertexId); 87 | const ColumnCoordinatesContainer* GetColumnCoordinates(VertexIdentifier vertexId) const; 88 | void SetColumnCoordinates(VertexIdentifier vertexId, ColumnCoordinatesContainer* columnCoordinates); 89 | 90 | // access to column costs of a vertex 91 | ColumnCostsContainer* GetColumnCosts(VertexIdentifier vertexId); 92 | const ColumnCostsContainer* GetColumnCosts(VertexIdentifier vertexId) const; 93 | void SetColumnCosts(VertexIdentifier vertexId, ColumnCostsContainer* columnCosts); 94 | 95 | // access to initial vertex position 96 | const CoordinateType& GetInitialVertexPosition(VertexIdentifier vertexId) const; 97 | ColumnPositionIdentifier GetInitialVertexPositionIdentifier(VertexIdentifier vertexId) const; 98 | void SetInitialVertexPositionIdentifier(VertexIdentifier vertexId, ColumnPositionIdentifier columnPositionId); 99 | 100 | // access to current vertex position 101 | const CoordinateType& GetCurrentVertexPosition(VertexIdentifier vertexId) const; 102 | ColumnPositionIdentifier GetCurrentVertexPositionIdentifier(VertexIdentifier vertexId) const; 103 | void SetCurrentVertexPositionIdentifier(VertexIdentifier vertexId, ColumnPositionIdentifier columnPositionId); 104 | 105 | // access to cells 106 | CellsContainer* GetCells(); 107 | const CellsContainer* GetCells() const; 108 | void SetCells(CellsContainer* cells); 109 | 110 | // access to individual cells 111 | CellIdentifier GetNumberOfCells() const; 112 | bool GetCell(CellIdentifier cellId, CellAutoPointer& cellPointer) const; 113 | void SetCell(CellIdentifier cellId, CellAutoPointer& cellPointer); 114 | 115 | // allow lookup of neighboring of columns on the surface 116 | using VertexIdentifierContainer = VectorContainer< unsigned int, VertexIdentifier >; 117 | const VertexIdentifierContainer* GetNeighbors(VertexIdentifier vertexId) const; 118 | void BuildNeighborLookupTable(); 119 | 120 | // todo: do we need cell links like provided by the itk::Mesh? 121 | //using PointCellLinksContainer = typename MeshTraits::PointCellLinksContainer; // todo: do we need this? 122 | //using CellLinksContainer = typename MeshTraits::CellLinksContainer; // todo: do we need this? 123 | 124 | protected: 125 | /** Constructor for use by New() method. */ 126 | OSFSurface() = default; 127 | ~OSFSurface() override = default; 128 | void PrintSelf(std::ostream& os, Indent indent) const override; 129 | 130 | typename VertexColumnCoordinatesContainer::Pointer m_VertexColumnCoordinatesContainer{ VertexColumnCoordinatesContainer::New() }; 131 | typename VertexColumnCostsContainer::Pointer m_VertexColumnCostsContainer{ VertexColumnCostsContainer::New() }; 132 | VertexPositionIdentifierContainer::Pointer m_VertexInitialPositionIdentifierContainer{ VertexPositionIdentifierContainer::New() }; 133 | VertexPositionIdentifierContainer::Pointer m_VertexCurrentPositionIdentifierContainer{ VertexPositionIdentifierContainer::New() }; 134 | typename CellsContainer::Pointer m_CellsContainer{ CellsContainer::New() }; 135 | 136 | void ReleaseCellsMemory(); 137 | 138 | using VertexIdentifierListContainer = VectorContainer< VertexIdentifier, typename VertexIdentifierContainer::Pointer >; 139 | VertexIdentifierListContainer::Pointer m_VertexNeighborLookupTable; 140 | 141 | private: 142 | void AddVertexNeighbors(VertexIdentifier vertex1, VertexIdentifier vertex2); 143 | 144 | }; // end class OSFSurface 145 | 146 | } // namespace 147 | 148 | #ifndef ITK_MANUAL_INSTANTIATION 149 | #include "itkOSFSurface.txx" 150 | #endif 151 | 152 | #endif 153 | 154 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkCenterNormalColumnBuilderFilter.txx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkCenterNormalColumnBuilderFilter_txx 19 | #define _itkCenterNormalColumnBuilderFilter_txx 20 | 21 | #include "itkCenterNormalColumnBuilderFilter.h" 22 | 23 | 24 | /* 25 | Differences from itkSurfaceNormalColumnBuilderFilter: 26 | 1. Normal for point to center rather surface outwards 27 | 2. No steps backward. 28 | 3. Define either step length of number of steps. One will define the other. 29 | 4. Must define the center of the region. 30 | */ 31 | 32 | namespace itk 33 | { 34 | 35 | //---------------------------------------------------------------------------- 36 | template 37 | void 38 | CenterNormalColumnBuilderFilter 39 | ::GenerateData() 40 | { 41 | if( this->GetInput()->GetNumberOfSurfaces()!=1 ) 42 | { 43 | itkWarningMacro("CenterNormalColumnBuilderFilter currently only supports one surface!"); 44 | } 45 | 46 | //Copy the basic surface information. 47 | this->CopyInputOSFGraphToOutputOSFGraphSurfaces(); 48 | 49 | //Create cells based on the vertices. 50 | BuildVertexToCellLookupTable(); 51 | 52 | OutputOSFGraphPointer output = this->GetOutput(); 53 | typename OSFSurface::Pointer surface = output->GetSurface(); 54 | 55 | //Build each column, one per vertex. 56 | for (VertexIdentifier vertexId=0; vertexIdGetNumberOfVertices(); vertexId++) 57 | { this->BuildColumn(vertexId);} 58 | 59 | } 60 | 61 | //---------------------------------------------------------------------------- 62 | template 63 | void 64 | CenterNormalColumnBuilderFilter 65 | ::BuildColumn(VertexIdentifier vertexId) 66 | { 67 | typename OSFSurface::ConstPointer inputSurface = this->GetInput()->GetSurface(); 68 | typename OSFSurface::Pointer outputSurface = this->GetOutput()->GetSurface(); 69 | 70 | using Coordinate = typename OSFSurface::CoordinateType; 71 | using ColumnCoordinatesContainer = typename OSFSurface::ColumnCoordinatesContainer; 72 | using ColumnCostsContainer = typename OSFSurface::ColumnCostsContainer; 73 | 74 | Coordinate initialPosition; 75 | initialPosition[0] = m_CenterPoint[0]; 76 | initialPosition[1] = m_CenterPoint[1]; 77 | initialPosition[2] = m_CenterPoint[2]; 78 | 79 | //Determine proper direction vector from center to vertex with magnitude 1. 80 | DirectionVector CenterNormalDirection = GetNormal(vertexId); 81 | auto columnPositions = ColumnCoordinatesContainer::New(); 82 | columnPositions->CreateIndex( m_NumberOfSteps-1 ); 83 | 84 | 85 | // build column coordinates 86 | // Given a vector of magnitude 1 away from the center and the center as an initial position, 87 | // multiply the vector by the number of steps (from 1 to the maximum number of nodes) and the 88 | // length of each step. 89 | 90 | // center outward 91 | for (unsigned int step=0; stepSetElement( step, currentPosition ); 95 | } 96 | 97 | //Apply these coordinates to the graph 98 | outputSurface->SetColumnCoordinates( vertexId, columnPositions ); 99 | 100 | //Apply default costs 101 | auto columnCosts = ColumnCostsContainer::New(); 102 | columnCosts->CreateIndex( columnPositions->Size()-1 ); 103 | outputSurface->SetColumnCosts( vertexId, columnCosts ); 104 | 105 | //Apply a default position at the centermost node 106 | outputSurface->SetInitialVertexPositionIdentifier( vertexId, 0 ); 107 | } 108 | 109 | //---------------------------------------------------------------------------- 110 | template 111 | typename CenterNormalColumnBuilderFilter::DirectionVector 112 | CenterNormalColumnBuilderFilter 113 | ::GetNormal(const VertexIdentifier vertexId) const 114 | { 115 | DirectionVector direction; 116 | direction.Fill(0.0); 117 | using Point = typename OSFSurface::CoordinateType; 118 | 119 | auto inputSurface = this->GetInput()->GetSurface(); 120 | 121 | Point centerPosition; 122 | centerPosition[0] = m_CenterPoint[0]; 123 | centerPosition[1] = m_CenterPoint[1]; 124 | centerPosition[2] = m_CenterPoint[2]; 125 | 126 | //From the center point to the vertex of this column is the outward normal direction 127 | //Use point subtraction to get a vector from center to vertex 128 | Point vertexPosition = inputSurface->GetInitialVertexPosition( vertexId ); 129 | 130 | direction[0] = vertexPosition[0] - centerPosition[0]; 131 | direction[1] = vertexPosition[1] - centerPosition[1]; 132 | direction[2] = vertexPosition[2] - centerPosition[2]; 133 | 134 | 135 | // make compiler happy/normalize resulting vector 136 | if (direction.GetSquaredNorm()>0) 137 | direction.Normalize(); 138 | return direction; 139 | } 140 | 141 | 142 | 143 | //---------------------------------------------------------------------------- 144 | //Pre-built function 145 | template 146 | void 147 | CenterNormalColumnBuilderFilter 148 | ::BuildVertexToCellLookupTable() 149 | { 150 | typename OSFSurface::ConstPointer inputSurface = this->GetInput()->GetSurface(); 151 | typename OSFSurface::CellsContainer::ConstPointer cells = inputSurface->GetCells(); 152 | typename OSFSurface::CellsContainer::ConstIterator cellItr = cells->Begin(); 153 | typename OSFSurface::CellsContainer::ConstIterator cellEnd = cells->End(); 154 | 155 | m_VertexToCellLookupTable.clear(); 156 | m_VertexToCellLookupTable.resize(cells->Size()); 157 | 158 | while ( cellItr!=cellEnd ) 159 | { 160 | const typename OSFSurface::CellType* cellPointer = cellItr.Value(); 161 | unsigned int numberOfPoints = cellPointer->GetNumberOfPoints(); 162 | if (numberOfPoints>1) 163 | { 164 | typename OSFSurface::CellType::PointIdConstIterator pointIdIterator = cellPointer->PointIdsBegin(); 165 | typename OSFSurface::CellType::PointIdConstIterator pointIdEnd = cellPointer->PointIdsEnd(); 166 | while( pointIdIterator!=pointIdEnd ) 167 | { 168 | m_VertexToCellLookupTable[ *pointIdIterator ].insert( cellItr.Index() ); 169 | ++pointIdIterator; 170 | } 171 | } 172 | 173 | ++cellItr; 174 | } 175 | } 176 | 177 | //---------------------------------------------------------------------------- 178 | template 179 | void 180 | CenterNormalColumnBuilderFilter 181 | ::PrintSelf(std::ostream& os, Indent indent) const 182 | { 183 | Superclass::PrintSelf(os,indent); 184 | // todo: implement 185 | } 186 | 187 | } // namespace 188 | 189 | #endif 190 | 191 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkMeshToOSFGraphFilter.txx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkMeshToOSFGraphFilter_txx 19 | #define _itkMeshToOSFGraphFilter_txx 20 | 21 | #include "itkMeshToOSFGraphFilter.h" 22 | 23 | namespace itk 24 | { 25 | 26 | //---------------------------------------------------------------------------- 27 | template 28 | MeshToOSFGraphFilter 29 | ::MeshToOSFGraphFilter() 30 | { 31 | this->ProcessObject::SetNumberOfRequiredInputs(1); 32 | 33 | OutputOSFGraphPointer output 34 | = dynamic_cast(this->MakeOutput(0).GetPointer()); 35 | 36 | this->ProcessObject::SetNumberOfRequiredOutputs(1); 37 | this->ProcessObject::SetNthOutput(0, output.GetPointer()); 38 | 39 | } 40 | 41 | //---------------------------------------------------------------------------- 42 | template 43 | void 44 | MeshToOSFGraphFilter 45 | ::SetInput(unsigned int idx, const InputMeshType* input) 46 | { 47 | // process object is not const-correct, the const_cast 48 | // is required here. 49 | this->ProcessObject::SetNthInput(idx, const_cast< InputMeshType * >(input) ); 50 | } 51 | 52 | //---------------------------------------------------------------------------- 53 | template 54 | const typename MeshToOSFGraphFilter::InputMeshType* 55 | MeshToOSFGraphFilter 56 | ::GetInput(unsigned int idx) 57 | { 58 | return dynamic_cast (this->ProcessObject::GetInput(idx)); 59 | } 60 | 61 | //---------------------------------------------------------------------------- 62 | template 63 | typename MeshToOSFGraphFilter::OutputOSFGraphType* 64 | MeshToOSFGraphFilter 65 | ::GetOutput() 66 | { 67 | return dynamic_cast (this->ProcessObject::GetOutput(0)); 68 | } 69 | 70 | //---------------------------------------------------------------------------- 71 | template 72 | void 73 | MeshToOSFGraphFilter 74 | ::GenerateOutputInformation() 75 | { 76 | // todo: do we have to do something here? 77 | } 78 | 79 | //---------------------------------------------------------------------------- 80 | template 81 | DataObject::Pointer 82 | MeshToOSFGraphFilter 83 | ::MakeOutput(DataObjectPointerArraySizeType) 84 | { 85 | OutputOSFGraphPointer outputOSFGraph = OutputOSFGraphType::New(); 86 | return dynamic_cast< DataObject *>( outputOSFGraph.GetPointer() ); 87 | } 88 | 89 | //---------------------------------------------------------------------------- 90 | template 91 | void 92 | MeshToOSFGraphFilter 93 | ::PrintSelf(std::ostream& os, Indent indent) const 94 | { 95 | Superclass::PrintSelf(os,indent); 96 | // todo: implement 97 | } 98 | 99 | //---------------------------------------------------------------------------- 100 | template 101 | void 102 | MeshToOSFGraphFilter 103 | ::GenerateData() 104 | { 105 | auto outputOSFGraph = this->GetOutput(); 106 | for (typename OutputOSFGraphType::SurfaceIdentifier surfaceId=0; surfaceIdGetNumberOfInputs(); surfaceId++) 107 | { 108 | InputMeshConstPointer currentInputSurface = this->GetInput(surfaceId); 109 | typename OutputOSFGraphType::OSFSurface::Pointer currentOutputSurface = outputOSFGraph->GetSurface(surfaceId); 110 | this->CopyInputMeshToOutputOSFSurfacePoints(currentInputSurface,currentOutputSurface); 111 | this->CopyInputMeshToOutputOSFSurfaceCells(currentInputSurface,currentOutputSurface); 112 | } 113 | 114 | } 115 | 116 | //---------------------------------------------------------------------------- 117 | template 118 | void 119 | MeshToOSFGraphFilter 120 | ::CopyInputMeshToOutputOSFSurfacePoints(InputMeshConstPointer mesh, typename OutputOSFGraphType::OSFSurface::Pointer osfSurface) 121 | { 122 | using PointIterator = typename TInputMesh::PointsContainer::ConstIterator; 123 | using PointType = typename TInputMesh::PointType; 124 | PointIterator pointIterator = mesh->GetPoints()->Begin(); 125 | PointIterator pointEnd = mesh->GetPoints()->End(); 126 | 127 | while( pointIterator != pointEnd ) 128 | { 129 | typename OutputOSFGraphType::OSFSurface::VertexIdentifier vertexId = pointIterator.Index(); 130 | PointType point = pointIterator.Value(); 131 | 132 | using ColumnCoordinatesContainerType = typename OutputOSFGraphType::OSFSurface::ColumnCoordinatesContainer; 133 | auto columnCoordinatesContainer = ColumnCoordinatesContainerType::New(); 134 | columnCoordinatesContainer->InsertElement(0, point ); 135 | osfSurface->SetColumnCoordinates(vertexId, columnCoordinatesContainer); 136 | using ColumnCostsContainerType = typename OutputOSFGraphType::OSFSurface::ColumnCostsContainer; 137 | auto columnCostsContainer = ColumnCostsContainerType::New(); 138 | columnCostsContainer->InsertElement(0, 0.0 ); 139 | osfSurface->SetColumnCosts(vertexId,columnCostsContainer); 140 | osfSurface->SetInitialVertexPositionIdentifier(vertexId,0); 141 | osfSurface->SetCurrentVertexPositionIdentifier(vertexId,0); 142 | 143 | pointIterator++; 144 | } 145 | } 146 | 147 | //---------------------------------------------------------------------------- 148 | template 149 | void 150 | MeshToOSFGraphFilter 151 | ::CopyInputMeshToOutputOSFSurfaceCells(InputMeshConstPointer mesh, typename OutputOSFGraphType::OSFSurface::Pointer osfSurface) 152 | { 153 | using OutputCellsContainer = typename OutputOSFGraphType::OSFSurface::CellsContainer; 154 | using InputCellsContainer = typename TInputMesh::CellsContainer; 155 | using CellAutoPointer = typename OutputOSFGraphType::OSFSurface::CellAutoPointer; 156 | 157 | //outputMesh->SetCellsAllocationMethod( OutputMeshType::CellsAllocatedDynamicallyCellByCell ); 158 | 159 | auto outputCells = OutputCellsContainer::New(); 160 | const InputCellsContainer * inputCells = mesh->GetCells(); 161 | 162 | if( inputCells ) 163 | { 164 | outputCells->Reserve( inputCells->Size() ); 165 | 166 | typename InputCellsContainer::ConstIterator inputItr = inputCells->Begin(); 167 | typename InputCellsContainer::ConstIterator inputEnd = inputCells->End(); 168 | 169 | typename OutputCellsContainer::Iterator outputItr = outputCells->Begin(); 170 | 171 | CellAutoPointer clone; 172 | 173 | while( inputItr != inputEnd ) 174 | { 175 | // outputItr.Value() = inputItr.Value(); 176 | // note: this comment is from itkMeshToMeshFilter // BUG: FIXME: Here we are copying a pointer, which is a mistake. What we should do is to clone the cell. 177 | inputItr.Value()->MakeCopy( clone ); 178 | outputItr.Value() = clone.ReleaseOwnership(); 179 | 180 | ++inputItr; 181 | ++outputItr; 182 | } 183 | 184 | osfSurface->SetCells( outputCells ); 185 | } 186 | } 187 | 188 | } // namespace 189 | 190 | #endif 191 | 192 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkOSFGraphToMeshFilter.txx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef __itkOSFGraphToMeshFilter_txx 19 | #define __itkOSFGraphToMeshFilter_txx 20 | 21 | #include "itkOSFGraphToMeshFilter.h" 22 | 23 | namespace itk 24 | { 25 | 26 | //---------------------------------------------------------------------------- 27 | template 28 | OSFGraphToMeshFilter 29 | ::OSFGraphToMeshFilter() : 30 | m_SurfaceType(CurrentSurface) 31 | { 32 | this->ProcessObject::SetNumberOfRequiredInputs(1); 33 | 34 | OutputMeshPointer output 35 | = dynamic_cast(this->MakeOutput(0).GetPointer()); 36 | 37 | this->ProcessObject::SetNumberOfRequiredOutputs(1); 38 | this->ProcessObject::SetNthOutput(0, output.GetPointer()); 39 | 40 | } 41 | 42 | //---------------------------------------------------------------------------- 43 | template 44 | DataObject::Pointer 45 | OSFGraphToMeshFilter 46 | ::MakeOutput(DataObjectPointerArraySizeType) 47 | { 48 | auto outputMesh = OutputMeshType::New(); 49 | return dynamic_cast< DataObject *>( outputMesh.GetPointer() ); 50 | } 51 | 52 | //---------------------------------------------------------------------------- 53 | template 54 | void 55 | OSFGraphToMeshFilter 56 | ::SetInput(const InputOSFGraphType* input) 57 | { 58 | // process object is not const-correct, the const_cast is required here. 59 | this->ProcessObject::SetNthInput(0, const_cast< InputOSFGraphType * >(input) ); 60 | } 61 | 62 | //---------------------------------------------------------------------------- 63 | template 64 | const typename OSFGraphToMeshFilter::InputOSFGraphType* 65 | OSFGraphToMeshFilter 66 | ::GetInput() 67 | { 68 | return dynamic_cast (this->ProcessObject::GetInput(0)); 69 | } 70 | 71 | //---------------------------------------------------------------------------- 72 | template 73 | typename OSFGraphToMeshFilter::OutputMeshType * 74 | OSFGraphToMeshFilter 75 | ::GetOutput(unsigned int idx) 76 | { 77 | return dynamic_cast 78 | (this->ProcessObject::GetOutput(idx)); 79 | } 80 | 81 | //---------------------------------------------------------------------------- 82 | template 83 | void 84 | OSFGraphToMeshFilter 85 | ::GenerateData() 86 | { 87 | InputOSFGraphConstPointer inputOSFGraph = this->GetInput(); 88 | for (typename InputOSFGraphType::SurfaceIdentifier surfaceId=0; surfaceIdGetNumberOfSurfaces(); surfaceId++) 89 | { 90 | OutputMeshPointer currentOutputSurface = this->GetOutput(surfaceId); 91 | // todo: we have to create the output meshes first in case we have multiple. One is already created per default in the constructor 92 | typename InputOSFGraphType::OSFSurface::ConstPointer currentInputSurface = inputOSFGraph->GetSurface(surfaceId); 93 | this->CopyInputOSFSurfaceToOutputMeshPoints(currentInputSurface, currentOutputSurface); 94 | this->CopyInputOSFSurfaceToOutputMeshCells(currentInputSurface, currentOutputSurface); 95 | } 96 | } 97 | 98 | //---------------------------------------------------------------------------- 99 | template 100 | void 101 | OSFGraphToMeshFilter 102 | ::GenerateOutputInformation() 103 | { 104 | // todo: do we have to do something here? 105 | // todo: does this actually create addititional output meshes depending on the number of surfaces in the input graph 106 | for (typename InputOSFGraphType::SurfaceIdentifier surfaceId=this->GetNumberOfOutputs(); surfaceIdGetInput()->GetNumberOfSurfaces(); surfaceId++) 107 | { 108 | OutputMeshPointer output = dynamic_cast(this->MakeOutput(surfaceId).GetPointer()); 109 | this->ProcessObject::SetNumberOfRequiredOutputs(this->GetInput()->GetNumberOfSurfaces()); 110 | this->ProcessObject::SetNthOutput(surfaceId, output.GetPointer()); 111 | } 112 | } 113 | 114 | //---------------------------------------------------------------------------- 115 | template 116 | void 117 | OSFGraphToMeshFilter 118 | ::CopyInputOSFSurfaceToOutputMeshPoints(typename InputOSFGraphType::OSFSurface::ConstPointer osfSurface, OutputMeshPointer mesh) 119 | { 120 | auto points = OutputMeshType::PointsContainer::New(); 121 | points->Reserve( osfSurface->GetNumberOfVertices() ); 122 | typename OutputMeshType::PointsContainer::Iterator pointIterator = points->Begin(); 123 | typename OutputMeshType::PointsContainer::Iterator pointEnd = points->End(); 124 | 125 | while ( pointIterator != pointEnd ) 126 | { 127 | typename InputOSFGraphType::OSFSurface::VertexIdentifier vertexId = pointIterator.Index(); 128 | typename InputOSFGraphType::OSFSurface::ColumnPositionIdentifier columnPositionId = 0; 129 | switch(m_SurfaceType) 130 | { 131 | case CurrentSurface: columnPositionId = osfSurface->GetCurrentVertexPositionIdentifier(vertexId); break; 132 | case InitialSurface: columnPositionId = osfSurface->GetInitialVertexPositionIdentifier(vertexId); break; 133 | case InnermostSurface: columnPositionId = 0; break; 134 | case OutermostSurface: columnPositionId = (osfSurface->GetNumberOfColumns(vertexId)>0) ? osfSurface->GetNumberOfColumns(vertexId) : 0; break; 135 | default: columnPositionId = osfSurface->GetCurrentVertexPositionIdentifier(vertexId); 136 | } 137 | pointIterator.Value() = osfSurface->GetColumnCoordinates(vertexId)->ElementAt(columnPositionId); 138 | ++pointIterator; 139 | } 140 | 141 | mesh->SetPoints(points); 142 | } 143 | 144 | //---------------------------------------------------------------------------- 145 | template 146 | void 147 | OSFGraphToMeshFilter 148 | ::CopyInputOSFSurfaceToOutputMeshCells(typename InputOSFGraphType::OSFSurface::ConstPointer osfSurface, OutputMeshPointer mesh) 149 | { 150 | using InputCellsContainer = typename InputOSFGraphType::OSFSurface::CellsContainer; 151 | using OutputCellsContainer = typename TOutputMesh::CellsContainer; 152 | using CellAutoPointer = typename InputOSFGraphType::OSFSurface::CellAutoPointer; 153 | 154 | mesh->SetCellsAllocationMethod( OutputMeshType::CellsAllocatedDynamicallyCellByCell ); 155 | 156 | auto outputCells = OutputCellsContainer::New(); 157 | const InputCellsContainer * inputCells = osfSurface->GetCells(); 158 | 159 | if( inputCells ) 160 | { 161 | outputCells->Reserve( inputCells->Size() ); 162 | 163 | typename InputCellsContainer::ConstIterator inputItr = inputCells->Begin(); 164 | typename InputCellsContainer::ConstIterator inputEnd = inputCells->End(); 165 | 166 | typename OutputCellsContainer::Iterator outputItr = outputCells->Begin(); 167 | 168 | CellAutoPointer clone; 169 | 170 | while( inputItr != inputEnd ) 171 | { 172 | // outputItr.Value() = inputItr.Value(); 173 | // note: this comment is from itkMeshToMeshFilter // BUG: FIXME: Here we are copying a pointer, which is a mistake. What we should do is to clone the cell. 174 | inputItr.Value()->MakeCopy( clone ); 175 | outputItr.Value() = clone.ReleaseOwnership(); 176 | 177 | ++inputItr; 178 | ++outputItr; 179 | } 180 | 181 | mesh->SetCells( outputCells ); 182 | } 183 | } 184 | 185 | //---------------------------------------------------------------------------- 186 | template 187 | void 188 | OSFGraphToMeshFilter 189 | ::PrintSelf(std::ostream& os, Indent indent) const 190 | { 191 | Superclass::PrintSelf(os,indent); 192 | // todo: implement 193 | } 194 | 195 | } // end namespace itk 196 | 197 | #endif 198 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkOSFGraph.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkOSFGraph_h 19 | #define _itkOSFGraph_h 20 | 21 | #include 22 | #include "itkOSFSurface.h" 23 | 24 | namespace itk 25 | { 26 | /**\class OSFGraph 27 | * \brief The class for holding the graph information. 28 | * \date 12/9/2014 29 | * \author Chrsitian Bauer 30 | * ? 31 | * Template parameters for class OSFGraph: 32 | * 33 | * - TCostType = ? 34 | * - TOSFSurfaceType = ? 35 | */ 36 | template > 37 | class ITK_EXPORT OSFGraph : public DataObject 38 | { 39 | public: 40 | using Self = OSFGraph; 41 | using Superclass = DataObject; 42 | using Pointer = SmartPointer< Self >; 43 | using ConstPointer = SmartPointer< const Self >; 44 | 45 | ITK_DISALLOW_COPY_AND_ASSIGN(OSFGraph); 46 | 47 | itkNewMacro( Self ); 48 | itkTypeMacro( OSFGraph, DataObject ); 49 | 50 | using IdentifierType = unsigned long; 51 | 52 | //-------------------------------------------------------------- 53 | // surfaces 54 | //-------------------------------------------------------------- 55 | using OSFSurface = TOSFSurfaceType; 56 | using VertexIdentifier = typename OSFSurface::VertexIdentifier; 57 | using ColumnPositionIdentifier = typename OSFSurface::ColumnPositionIdentifier; 58 | using SurfaceIdentifier = IdentifierType; 59 | using OSFSurfacePointer = typename OSFSurface::Pointer; 60 | using OSFSurfaceConstPointer = typename OSFSurface::ConstPointer; 61 | using SurfacesContainer = VectorContainer< SurfaceIdentifier, OSFSurfacePointer >; 62 | 63 | // access to surfaces 64 | SurfaceIdentifier GetNumberOfSurfaces() const; 65 | OSFSurface* GetSurface(SurfaceIdentifier surfaceId=0); 66 | const OSFSurface* GetSurface(SurfaceIdentifier surfaceId=0) const; 67 | void SetSurface(OSFSurfacePointer surface) {return this->SetSurface(0, surface);}; 68 | void SetSurface(SurfaceIdentifier surfaceId, OSFSurface* surface); 69 | 70 | //-------------------------------------------------------------- 71 | // graph nodes and edges 72 | //-------------------------------------------------------------- 73 | using GraphCosts = TCostType; 74 | using GraphNodeIdentifier = IdentifierType; 75 | using GraphEdgeIdentifier = IdentifierType; 76 | 77 | class GraphNode 78 | { 79 | public: 80 | GraphNode() = default; 81 | GraphNode(SurfaceIdentifier surfaceId_, VertexIdentifier vertexId_, ColumnPositionIdentifier positionId_, GraphCosts cap_source_, GraphCosts cap_sink_) : 82 | surfaceId(surfaceId_), vertexId(vertexId_), positionId(positionId_), cap_source(cap_source_), cap_sink(cap_sink_) {}; 83 | SurfaceIdentifier surfaceId{ 0 }; 84 | VertexIdentifier vertexId{ 0 }; 85 | ColumnPositionIdentifier positionId{ 0 }; 86 | GraphCosts cap_source{ 0 }; 87 | GraphCosts cap_sink{ 0 }; 88 | }; 89 | 90 | class GraphEdge 91 | { 92 | public: 93 | GraphEdge() = default; 94 | GraphEdge(GraphNodeIdentifier startNodeId_, GraphNodeIdentifier endNodeId_, GraphCosts cap_, GraphCosts rev_cap_) : 95 | startNodeId(startNodeId_), endNodeId(endNodeId_), cap(cap_), rev_cap(rev_cap_) {}; 96 | GraphNodeIdentifier startNodeId{ 0 }; 97 | GraphNodeIdentifier endNodeId{ 0 }; 98 | GraphCosts cap{ 0 }; 99 | GraphCosts rev_cap{ 0 }; 100 | }; 101 | 102 | using GraphNodesContainer = VectorContainer< GraphNodeIdentifier, GraphNode >; 103 | using GraphEdgesContainer = VectorContainer< GraphEdgeIdentifier, GraphEdge >; 104 | 105 | // access to nodes 106 | GraphNodeIdentifier GetNumberOfNodes() const; 107 | GraphNode& GetNode(GraphNodeIdentifier nodeId); 108 | const GraphNode& GetNode(GraphNodeIdentifier nodeId) const; 109 | void SetNode(GraphNodeIdentifier nodeId, const GraphNode& node); 110 | GraphNodesContainer* GetNodes(); 111 | const GraphNodesContainer* GetNodes() const; 112 | void SetNodes(GraphNodesContainer* nodes); 113 | 114 | // access to edges 115 | GraphEdgeIdentifier GetNumberOfEdges() const; 116 | GraphEdge& GetEdge(GraphEdgeIdentifier edgeId); 117 | const GraphEdge& GetEdge(GraphEdgeIdentifier edgeId) const; 118 | void SetEdge(GraphEdgeIdentifier edgeId, const GraphEdge& edge); 119 | GraphEdgesContainer* GetEdges(); 120 | const GraphEdgesContainer* GetEdges() const; 121 | void SetEdges(GraphEdgesContainer* edges); 122 | 123 | // utility function for fast lookup of graph nodes/edges associated with a SurfaceVertexColumnPosition 124 | // after graph construction (nodes/edges) the internally used lookup table has to be build first 125 | void BuildGraphNodeIdentifierLookupTable(); 126 | GraphNodeIdentifier GetNodeIdentifer(SurfaceIdentifier surfaceId, VertexIdentifier vertexId, ColumnPositionIdentifier columnPositionId) const; 127 | GraphNode& GetNode(SurfaceIdentifier surfaceId, VertexIdentifier vertexId, ColumnPositionIdentifier columnPositionId); 128 | const GraphNode& GetNode(SurfaceIdentifier surfaceId, VertexIdentifier vertexId, ColumnPositionIdentifier columnPositionId) const; 129 | 130 | /** Type used to define Regions */ 131 | using RegionType = long; 132 | 133 | void Initialize(void) override; 134 | 135 | /** Get the maximum number of regions that this data can be 136 | * separated into. */ 137 | itkGetConstMacro( MaximumNumberOfRegions, RegionType ); 138 | 139 | /** Set the requested region from this data object to match the requested 140 | * region of the data object passed in as a parameter. This method 141 | * implements the API from DataObject. The data object parameter must be 142 | * castable to a PointSet. */ 143 | //virtual void SetRequestedRegion(DataObject *data); // TODO: this causes troubles when creating python binding for c++ overloading 144 | 145 | /** Methods to manage streaming. */ 146 | void UpdateOutputInformation() override; 147 | void SetRequestedRegionToLargestPossibleRegion() override; 148 | void CopyInformation(const DataObject *data) override; 149 | void Graft(const DataObject *data) override; 150 | bool RequestedRegionIsOutsideOfTheBufferedRegion() override; 151 | bool VerifyRequestedRegion() override; 152 | 153 | /** Set/Get the Requested region */ 154 | //virtual void SetRequestedRegion( const RegionType & region ); // TODO: this causes troubles when creating python binding for c++ overloading 155 | itkGetConstMacro( RequestedRegion, RegionType ); 156 | 157 | /** Set/Get the Buffered region */ 158 | virtual void SetBufferedRegion( const RegionType & region ); 159 | itkGetConstMacro( BufferedRegion, RegionType ); 160 | 161 | protected: 162 | /** Constructor for use by New() method. */ 163 | OSFGraph() = default; 164 | ~OSFGraph() override = default; 165 | void PrintSelf(std::ostream& os, Indent indent) const override; 166 | 167 | typename SurfacesContainer::Pointer m_SurfacesContainer{ SurfacesContainer::New() }; 168 | typename GraphNodesContainer::Pointer m_GraphNodesContainer{ GraphNodesContainer::New() }; 169 | typename GraphEdgesContainer::Pointer m_GraphEdgesContainer{ GraphEdgesContainer::New() }; 170 | 171 | std::vector< std::vector< std::vector< GraphNodeIdentifier > > > m_GraphNodeIdentifierLookupTable; // todo: probably not optimal data structure but should be sufficient 172 | 173 | // If the RegionType is ITK_UNSTRUCTURED_REGION, then the following 174 | // variables represent the maximum number of region that the data 175 | // object can be broken into, which region out of how many is 176 | // currently in the buffered region, and the number of regions and 177 | // the specific region requested for the update. Data objects that 178 | // do not support any division of the data can simply leave the 179 | // MaximumNumberOfRegions as 1. The RequestedNumberOfRegions and 180 | // RequestedRegion are used to define the currently requested 181 | // region. The LargestPossibleRegion is always requested region = 0 182 | // and number of regions = 1; 183 | RegionType m_MaximumNumberOfRegions{ 1 }; 184 | RegionType m_NumberOfRegions{ 1 }; 185 | RegionType m_RequestedNumberOfRegions{ 0 }; 186 | RegionType m_BufferedRegion{ -1 }; 187 | RegionType m_RequestedRegion{ -1 }; 188 | 189 | private: 190 | 191 | }; // end class OSFGraph 192 | 193 | } // end namespace itk 194 | 195 | #ifndef ITK_MANUAL_INSTANTIATION 196 | #include "itkOSFGraph.txx" 197 | #endif 198 | 199 | #endif 200 | 201 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkSimpleOSFGraphBuilderFilter.txx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkSimpleOSFGraphBuilderFilter_txx 19 | #define _itkSimpleOSFGraphBuilderFilter_txx 20 | 21 | #include "itkSimpleOSFGraphBuilderFilter.h" 22 | #include "itkLinearInterpolateImageFunction.h" 23 | #include "itkNumericTraits.h" 24 | 25 | namespace itk 26 | { 27 | //---------------------------------------------------------------------------- 28 | template 29 | void 30 | SimpleOSFGraphBuilderFilter 31 | ::GenerateData() 32 | { 33 | this->CopyInputOSFGraphToOutputOSFGraphSurfaces(); 34 | auto output = this->GetOutput(); 35 | 36 | // create nodes for columns 37 | for (SurfaceIdentifier surfaceId=0; surfaceIdGetNumberOfSurfaces(); surfaceId++) 38 | { 39 | typename OSFSurface::Pointer surface = output->GetSurface(surfaceId); 40 | for (VertexIdentifier vertexId=0; vertexIdGetNumberOfVertices(); vertexId++) 41 | this->CreateNodesForColumn(surfaceId, vertexId); 42 | } 43 | output->BuildGraphNodeIdentifierLookupTable(); 44 | 45 | // create intra-column arcs 46 | for (SurfaceIdentifier surfaceId=0; surfaceIdGetNumberOfSurfaces(); surfaceId++) 47 | { 48 | typename OSFSurface::Pointer surface = output->GetSurface(surfaceId); 49 | for (VertexIdentifier vertexId=0; vertexIdGetNumberOfVertices(); vertexId++) 50 | this->CreateIntraColumnArcsForColumn(surfaceId, vertexId); 51 | } 52 | 53 | // create inter-column arcs 54 | for (SurfaceIdentifier surfaceId=0; surfaceIdGetNumberOfSurfaces(); surfaceId++) 55 | { 56 | typename OSFSurface::Pointer surface = output->GetSurface(surfaceId); 57 | surface->BuildNeighborLookupTable(); 58 | for (VertexIdentifier vertexId=0; vertexIdGetNumberOfVertices(); vertexId++) 59 | this->CreateInterColumnArcsForColumn(surfaceId, vertexId); 60 | } 61 | 62 | } 63 | 64 | //---------------------------------------------------------------------------- 65 | template 66 | void 67 | SimpleOSFGraphBuilderFilter 68 | ::CreateNodesForColumn(SurfaceIdentifier surfaceId, VertexIdentifier vertexId) 69 | { 70 | using GraphNode = typename OutputOSFGraphType::GraphNode; 71 | 72 | auto output = this->GetOutput(); 73 | typename OSFSurface::ColumnCostsContainer::ConstPointer columnCosts = output->GetSurface(surfaceId)->GetColumnCosts(vertexId); 74 | typename OSFSurface::ColumnCostsContainer::ConstIterator columnCostsItr = columnCosts->Begin(); 75 | typename OSFSurface::ColumnCostsContainer::ConstIterator columnCostsEnd = columnCosts->End(); 76 | typename OutputOSFGraphType::GraphNodesContainer::Pointer graphNodes = output->GetNodes(); 77 | typename OutputOSFGraphType::GraphNodeIdentifier startNodeIndex = graphNodes->Size(); 78 | graphNodes->Reserve( graphNodes->Size()+columnCosts->Size() ); 79 | 80 | if (columnCosts->Size()>0) 81 | { 82 | typename OutputOSFGraphType::GraphCosts weight = 0; 83 | typename OutputOSFGraphType::GraphCosts previousNodeCost = columnCostsItr.Value(); 84 | graphNodes->SetElement( startNodeIndex++, GraphNode(surfaceId, vertexId, columnCostsItr->Index(), -m_ColumnBasedNodeWeight, 0) ); // set node of base to default value 85 | ++columnCostsItr; 86 | while (columnCostsItr!=columnCostsEnd) 87 | { 88 | weight = columnCostsItr.Value()-previousNodeCost; 89 | if (weight>0) // non-negative -> connect to t 90 | graphNodes->SetElement( startNodeIndex++, GraphNode(surfaceId, vertexId, columnCostsItr->Index(), 0.0, weight) ); 91 | else // negative -> connect to s 92 | graphNodes->SetElement( startNodeIndex++, GraphNode(surfaceId, vertexId, columnCostsItr->Index(), -weight, 0.0) ); 93 | previousNodeCost = columnCostsItr.Value(); 94 | ++columnCostsItr; 95 | } 96 | } 97 | 98 | } 99 | 100 | //---------------------------------------------------------------------------- 101 | template 102 | void 103 | SimpleOSFGraphBuilderFilter 104 | ::CreateIntraColumnArcsForColumn(SurfaceIdentifier surfaceId, VertexIdentifier vertexId) 105 | { 106 | //Edges along columns, from node to node, outside to inside, with infinite capacity 107 | //These relate the nodes on the column in the graph, allowing for selection of a single one 108 | using GraphEdge = typename OutputOSFGraphType::GraphEdge; 109 | using GraphNodeIdentifier= typename OutputOSFGraphType::GraphNodeIdentifier; 110 | 111 | auto output = this->GetOutput(); 112 | typename OSFSurface::ColumnPositionIdentifier numColumnPositions = output->GetSurface(surfaceId)->GetNumberOfColumns(vertexId); 113 | typename OutputOSFGraphType::GraphEdgesContainer::Pointer graphEdges = output->GetEdges(); 114 | typename OutputOSFGraphType::GraphEdgeIdentifier startEdgeIndex = graphEdges->Size(); 115 | graphEdges->Reserve( graphEdges->Size()+numColumnPositions-1 ); 116 | 117 | for (typename OSFSurface::ColumnPositionIdentifier columnPositionId=1; columnPositionIdGetNodeIdentifer(surfaceId, vertexId, columnPositionId); 120 | GraphNodeIdentifier endNodeId = output->GetNodeIdentifer(surfaceId, vertexId, columnPositionId-1); 121 | graphEdges->SetElement( startEdgeIndex++, GraphEdge( startNodeId, endNodeId, m_Infinity, 0) ); 122 | } 123 | 124 | } 125 | 126 | //---------------------------------------------------------------------------- 127 | template 128 | void 129 | SimpleOSFGraphBuilderFilter 130 | ::CreateInterColumnArcsForColumn(SurfaceIdentifier surfaceId, VertexIdentifier vertexId) 131 | { 132 | using GraphEdge = typename OutputOSFGraphType::GraphEdge; 133 | using GraphNodeIdentifier = typename OutputOSFGraphType::GraphNodeIdentifier; 134 | 135 | auto output = this->GetOutput(); 136 | typename OSFSurface::ColumnPositionIdentifier numColumnPositions = output->GetSurface(surfaceId)->GetNumberOfColumns(vertexId); 137 | typename OSFSurface::VertexIdentifierContainer::ConstPointer neighbors = output->GetSurface(surfaceId)->GetNeighbors(vertexId); 138 | typename OutputOSFGraphType::GraphEdgesContainer::Pointer graphEdges = output->GetEdges(); 139 | 140 | for (typename OSFSurface::VertexIdentifierContainer::ConstIterator neighborItr=neighbors->Begin(); neighborItr!=neighbors->End(); ++neighborItr) 141 | { 142 | // add hard smoothness constraints 143 | if (m_SmoothnessConstraint!=itk::NumericTraits::max()) 144 | { 145 | for (typename OSFSurface::ColumnPositionIdentifier columnPositionId=0; columnPositionIdGetNodeIdentifer(surfaceId, vertexId, columnPositionId); 148 | 149 | // note: computation of columnPositionId for the neighbor node should include the initialVertexPositionId 150 | GraphNodeIdentifier endNodeId = output->GetNodeIdentifer(surfaceId, neighborItr.Value(), typename OSFSurface::ColumnPositionIdentifier(std::max( (int)columnPositionId-(int)m_SmoothnessConstraint, 0)) ); 151 | graphEdges->InsertElement( graphEdges->Size(), GraphEdge( startNodeId, endNodeId, m_Infinity, 0) ); 152 | } 153 | } 154 | // add soft smoothness penalty term 155 | if (m_SoftSmoothnessPenalty>0.0 && neighborItr.Value()>vertexId) 156 | { 157 | for (typename OSFSurface::ColumnPositionIdentifier columnPositionId=0; columnPositionIdGetNodeIdentifer(surfaceId, vertexId, columnPositionId); 160 | 161 | // note: computation of columnPositionId for the neighbor node should include the initialVertexPositionId 162 | GraphNodeIdentifier endNodeId = output->GetNodeIdentifer(surfaceId, neighborItr.Value(), columnPositionId ); 163 | graphEdges->InsertElement( graphEdges->Size(), GraphEdge( startNodeId, endNodeId, m_SoftSmoothnessPenalty, m_SoftSmoothnessPenalty) ); 164 | } 165 | } 166 | } 167 | } 168 | 169 | //---------------------------------------------------------------------------- 170 | template 171 | void 172 | SimpleOSFGraphBuilderFilter 173 | ::PrintSelf(std::ostream& os, Indent indent) const 174 | { 175 | Superclass::PrintSelf(os,indent); 176 | // todo: implement 177 | } 178 | 179 | } // namespace 180 | 181 | #endif 182 | 183 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/itkOSFGraphToOSFGraphFilter.txx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _itkOSFGraphToOSFGraphFilter_txx 19 | #define _itkOSFGraphToOSFGraphFilter_txx 20 | 21 | #include "itkOSFGraphToOSFGraphFilter.h" 22 | 23 | namespace itk 24 | { 25 | 26 | //---------------------------------------------------------------------------- 27 | template 28 | OSFGraphToOSFGraphFilter 29 | ::OSFGraphToOSFGraphFilter() 30 | { 31 | // Modify superclass default values, can be overridden by subclasses 32 | this->SetNumberOfRequiredInputs(1); 33 | } 34 | 35 | //---------------------------------------------------------------------------- 36 | template 37 | void 38 | OSFGraphToOSFGraphFilter 39 | ::SetInput(unsigned int idx, const InputOSFGraphType* input) 40 | { 41 | // process object is not const-correct, the const_cast is required here. 42 | this->ProcessObject::SetNthInput(idx, const_cast< TInputOSFGraph * >(input) ); 43 | } 44 | 45 | //---------------------------------------------------------------------------- 46 | template 47 | const typename OSFGraphToOSFGraphFilter::InputOSFGraphType* 48 | OSFGraphToOSFGraphFilter 49 | ::GetInput(unsigned int idx) const 50 | { 51 | if (this->GetNumberOfInputs() < 1) 52 | { 53 | return 0; 54 | } 55 | return dynamic_cast (this->ProcessObject::GetInput(idx)); 56 | } 57 | 58 | //---------------------------------------------------------------------------- 59 | template 60 | typename OSFGraphToOSFGraphFilter::OutputOSFGraphType* 61 | OSFGraphToOSFGraphFilter 62 | ::GetOutput(unsigned int idx) 63 | { 64 | if (this->GetNumberOfOutputs() < 1) 65 | { 66 | return 0; 67 | } 68 | return dynamic_cast (this->ProcessObject::GetOutput(idx)); 69 | } 70 | 71 | //---------------------------------------------------------------------------- 72 | template 73 | void 74 | OSFGraphToOSFGraphFilter 75 | ::CopyInputOSFGraphToOutputOSFGraphSurfaces() 76 | { 77 | auto inputOSFGraph = this->GetInput(); 78 | auto outputOSFGraph = this->GetOutput(); 79 | for (typename OutputOSFGraphType::SurfaceIdentifier surfaceId=0; surfaceIdGetNumberOfSurfaces(); surfaceId++) 80 | { 81 | OSFSurfaceConstPointer currentInputSurface = inputOSFGraph->GetSurface(surfaceId); 82 | OSFSurfacePointer currentOutputSurface = outputOSFGraph->GetSurface(surfaceId); 83 | this->CopyInputOSFGraphToOutputOSFGraphSurface( currentInputSurface, currentOutputSurface ); 84 | } 85 | } 86 | 87 | //---------------------------------------------------------------------------- 88 | template 89 | void 90 | OSFGraphToOSFGraphFilter 91 | ::CopyInputOSFGraphToOutputOSFGraphSurface(OSFSurfaceConstPointer inputOSFSurface, OSFSurfacePointer outputOSFSurface) 92 | { 93 | // copy vertex information 94 | typename OSFSurface::VertexIdentifier numVertices = inputOSFSurface->GetNumberOfVertices(); 95 | for (typename OSFSurface::VertexIdentifier vertexId=0; vertexIdGetColumnCoordinates( vertexId ); 101 | if (inputPoints) 102 | { 103 | typename InputColumnCoordinatesContainerType::ConstIterator inputItr = inputPoints->Begin(); 104 | typename InputColumnCoordinatesContainerType::ConstIterator inputEnd = inputPoints->End(); 105 | using OutputColumnCoordinatesContainerType = typename OutputOSFGraphType::OSFSurface::ColumnCoordinatesContainer; 106 | typename OutputColumnCoordinatesContainerType::Pointer outputPoints = OutputColumnCoordinatesContainerType::New(); 107 | outputPoints->Reserve( inputPoints->Size() ); 108 | typename OutputColumnCoordinatesContainerType::Iterator outputItr = outputPoints->Begin(); 109 | while (inputItr!=inputEnd) 110 | { 111 | outputItr.Value() = inputItr.Value(); 112 | ++inputItr; ++outputItr; 113 | } 114 | outputOSFSurface->SetColumnCoordinates( vertexId, outputPoints ); 115 | } 116 | } 117 | 118 | // copy column point costs 119 | { 120 | using InputColumnCostsContainerType = typename InputOSFGraphType::OSFSurface::ColumnCostsContainer; 121 | typename InputColumnCostsContainerType::ConstPointer inputCosts = inputOSFSurface->GetColumnCosts( vertexId ); 122 | if (inputCosts) 123 | { 124 | typename InputColumnCostsContainerType::ConstIterator inputItr = inputCosts->Begin(); 125 | typename InputColumnCostsContainerType::ConstIterator inputEnd = inputCosts->End(); 126 | using OutputColumnCostsContainerType = typename OutputOSFGraphType::OSFSurface::ColumnCostsContainer; 127 | typename OutputColumnCostsContainerType::Pointer outputCosts = OutputColumnCostsContainerType::New(); 128 | outputCosts->Reserve( inputCosts->Size() ); 129 | typename OutputColumnCostsContainerType::Iterator outputItr = outputCosts->Begin(); 130 | while (inputItr!=inputEnd) 131 | { 132 | outputItr.Value() = inputItr.Value(); 133 | ++inputItr; ++outputItr; 134 | } 135 | outputOSFSurface->SetColumnCosts( vertexId, outputCosts ); 136 | } 137 | } 138 | 139 | outputOSFSurface->SetInitialVertexPositionIdentifier( vertexId, inputOSFSurface->GetInitialVertexPositionIdentifier(vertexId) ); 140 | outputOSFSurface->SetCurrentVertexPositionIdentifier( vertexId, inputOSFSurface->GetCurrentVertexPositionIdentifier(vertexId) ); 141 | } 142 | 143 | // copy cells 144 | using OutputCellsContainer = typename OutputOSFGraphType::OSFSurface::CellsContainer; 145 | using InputCellsContainer = typename InputOSFGraphType::OSFSurface::CellsContainer; 146 | using CellAutoPointer = typename OutputOSFGraphType::OSFSurface::CellAutoPointer; 147 | 148 | auto outputCells = OutputCellsContainer::New(); 149 | const InputCellsContainer * inputCells = inputOSFSurface->GetCells(); 150 | 151 | if( inputCells ) 152 | { 153 | outputCells->Reserve( inputCells->Size() ); 154 | 155 | typename InputCellsContainer::ConstIterator inputItr = inputCells->Begin(); 156 | typename InputCellsContainer::ConstIterator inputEnd = inputCells->End(); 157 | typename OutputCellsContainer::Iterator outputItr = outputCells->Begin(); 158 | 159 | CellAutoPointer clone; 160 | 161 | while( inputItr != inputEnd ) 162 | { 163 | inputItr.Value()->MakeCopy( clone ); 164 | outputItr.Value() = clone.ReleaseOwnership(); 165 | 166 | ++inputItr; 167 | ++outputItr; 168 | } 169 | 170 | outputOSFSurface->SetCells( outputCells ); 171 | } 172 | } 173 | //---------------------------------------------------------------------------- 174 | template 175 | void 176 | OSFGraphToOSFGraphFilter 177 | ::CopyInputOSFGraphToOutputOSFGraphGraph() 178 | { 179 | // copy nodes 180 | using GraphNodesContainer = typename OutputOSFGraphType::GraphNodesContainer; 181 | typename GraphNodesContainer::ConstPointer inputGraphNodes = this->GetInput()->GetNodes(); 182 | typename GraphNodesContainer::Pointer outputGraphNodes = GraphNodesContainer::New(); 183 | 184 | if (inputGraphNodes) 185 | { 186 | outputGraphNodes->Reserve( inputGraphNodes->Size() ); 187 | typename GraphNodesContainer::ConstIterator inputItr = inputGraphNodes->Begin(); 188 | typename GraphNodesContainer::ConstIterator inputEnd = inputGraphNodes->End(); 189 | typename GraphNodesContainer::Iterator outputItr = outputGraphNodes->Begin(); 190 | while( inputItr != inputEnd ) 191 | { 192 | outputItr.Value() = inputItr.Value(); 193 | ++inputItr; 194 | ++outputItr; 195 | } 196 | this->GetOutput()->SetNodes( outputGraphNodes ); 197 | } 198 | 199 | // copy edges 200 | using GraphEdgesContainer = typename OutputOSFGraphType::GraphEdgesContainer; 201 | typename GraphEdgesContainer::ConstPointer inputGraphEdges = this->GetInput()->GetEdges(); 202 | typename GraphEdgesContainer::Pointer outputGraphEdges = GraphEdgesContainer::New(); 203 | 204 | if (inputGraphEdges) 205 | { 206 | outputGraphEdges->Reserve( inputGraphEdges->Size() ); 207 | typename GraphEdgesContainer::ConstIterator inputItr = inputGraphEdges->Begin(); 208 | typename GraphEdgesContainer::ConstIterator inputEnd = inputGraphEdges->End(); 209 | typename GraphEdgesContainer::Iterator outputItr = outputGraphEdges->Begin(); 210 | while( inputItr != inputEnd ) 211 | { 212 | outputItr.Value() = inputItr.Value(); 213 | ++inputItr; 214 | ++outputItr; 215 | } 216 | this->GetOutput()->SetEdges( outputGraphEdges ); 217 | } 218 | } 219 | 220 | //---------------------------------------------------------------------------- 221 | template 222 | void 223 | OSFGraphToOSFGraphFilter 224 | ::PrintSelf(std::ostream& os, Indent indent) const 225 | { 226 | Superclass::PrintSelf(os,indent); 227 | // todo: implement 228 | } 229 | 230 | } // namespace 231 | 232 | #endif 233 | 234 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/logismos_graph.cxx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | namespace LOGISMOS{ 19 | 20 | //////////////////////////////////////////////////////// 21 | template 22 | _Cap graph<_Cap, _DataChunkSize, _PtrChunkSize>::solve() 23 | { 24 | // make sure we start from correct initial condition 25 | m_orphan_nodes.clear(); 26 | 27 | node* p_node; 28 | edge* p_edge; 29 | 30 | p_node=m_nodes.scan_first(); 31 | while(p_node){ 32 | if(p_node->has_parent() == false || p_node->is_active() == false) 33 | p_edge = 0; 34 | else{ 35 | p_edge = grow_active_node(p_node); 36 | m_clock++; 37 | } 38 | 39 | if(p_edge){ // will process same active node in next iteration 40 | augment_path(p_edge); 41 | while(m_orphan_nodes.empty() == false){ 42 | adopt_orphan(m_orphan_nodes.front()); 43 | m_orphan_nodes.pop_front(); 44 | } 45 | } 46 | else{ // ready to process next node 47 | p_node->set_active(false); 48 | p_node = m_nodes.scan_next(); 49 | } 50 | } 51 | 52 | while(m_active_nodes.empty() == false){ 53 | p_node = m_active_nodes.front(); // p_node->is_active() is always true here 54 | if(p_node->has_parent() == false) // a node in the queue may lose parent during adopt_orphan() 55 | p_edge = 0; 56 | else{ 57 | p_edge = grow_active_node(p_node); 58 | m_clock++; 59 | } 60 | 61 | if(p_edge){ // will process same active node in next iteration 62 | augment_path(p_edge); 63 | while(m_orphan_nodes.empty() == false){ 64 | adopt_orphan(m_orphan_nodes.front()); 65 | m_orphan_nodes.pop_front(); 66 | } 67 | } 68 | else{ // ready to process next node in active queue 69 | p_node->set_active(false); 70 | m_active_nodes.pop_front(); 71 | } 72 | } 73 | return m_flow; 74 | } 75 | 76 | //////////////////////////////////////////////////////// 77 | template 78 | typename graph<_Cap, _DataChunkSize, _PtrChunkSize>::edge* graph<_Cap, _DataChunkSize, _PtrChunkSize>::grow_active_node(node* node_i) 79 | { 80 | bool i_is_sink = node_i->is_sink(); 81 | 82 | for(edge** edge_dptr = node_i->m_out_edges->scan_first(); edge_dptr; edge_dptr = node_i->m_out_edges->scan_next()){ 83 | edge* p_edge = *edge_dptr; 84 | _Cap cap = (i_is_sink) ? p_edge->m_sister->m_rcap : p_edge->m_rcap; 85 | if(cap == 0) continue; // only check edge with residual capacity 86 | 87 | node* node_j = p_edge->m_head; 88 | if(node_j->has_parent() == false){ 89 | node_j->set_sink(i_is_sink); // assign j to the same tree 90 | node_j->m_par_edge = p_edge->m_sister; 91 | node_j->m_time = node_i->m_time; 92 | node_j->m_dist = node_i->m_dist + 1; 93 | activate(node_j); 94 | } 95 | else if(node_j->is_sink() != i_is_sink){ 96 | // return the edge from a source node to a sink node 97 | if(i_is_sink) return p_edge->m_sister; 98 | else return p_edge; 99 | } 100 | else if(node_j->m_time <= node_i->m_time && node_j->m_dist > node_i->m_dist){ 101 | // trying to make the distance from j to the terminal node shorter 102 | node_j->m_par_edge = p_edge->m_sister; 103 | node_j->m_time = node_i->m_time; 104 | node_j->m_dist = node_i->m_dist + 1; 105 | } 106 | } 107 | return 0; // found NO edge connecting source and sink trees 108 | } 109 | 110 | //////////////////////////////////////////////////////// 111 | template 112 | void graph<_Cap, _DataChunkSize, _PtrChunkSize>::augment_path(edge* mid_edge) 113 | { 114 | edge* p_edge; 115 | _Cap cap; 116 | _Cap eps = std::numeric_limits<_Cap>::epsilon(); 117 | _Cap bottleneck = mid_edge->m_rcap; // initial bottleneck 118 | 119 | // find bottleneck residual capacity of source tree 120 | node* p_node = mid_edge->m_sister->m_head; 121 | while(p_node->is_terminal() == false){ 122 | p_edge = p_node->m_par_edge; 123 | cap = p_edge->m_sister->m_rcap; 124 | if(bottleneck > cap) bottleneck = cap; 125 | p_node = p_edge->m_head; 126 | } 127 | if(bottleneck > p_node->m_rcap) bottleneck = p_node->m_rcap; 128 | 129 | // find bottleneck residual capacity of sink tree 130 | p_node = mid_edge->m_head; 131 | while(p_node->is_terminal() == false){ 132 | p_edge = p_node->m_par_edge; 133 | cap = p_edge->m_rcap; 134 | if(bottleneck > cap) bottleneck = cap; 135 | p_node = p_edge->m_head; 136 | } 137 | if(bottleneck > -(p_node->m_rcap)) bottleneck = -(p_node->m_rcap); 138 | 139 | 140 | // augment the middle edge 141 | mid_edge->m_rcap -= bottleneck; 142 | mid_edge->m_sister->m_rcap += bottleneck; 143 | 144 | // augment the source tree 145 | p_node = mid_edge->m_sister->m_head; 146 | while(p_node->is_terminal() == false){ 147 | p_edge = p_node->m_par_edge; 148 | p_edge->m_rcap += bottleneck; 149 | p_edge->m_sister->m_rcap -= bottleneck; 150 | if(p_edge->m_sister->m_rcap <= eps){ 151 | p_edge->m_sister->m_rcap = 0; 152 | mark_orphan(p_node); 153 | } 154 | p_node = p_edge->m_head; 155 | } 156 | p_node->m_rcap -= bottleneck; 157 | if(p_node->m_rcap <= eps){ 158 | p_node->m_rcap = 0; 159 | mark_orphan(p_node); 160 | } 161 | 162 | // augment the sink tree 163 | p_node = mid_edge->m_head; 164 | while(p_node->is_terminal() == false){ 165 | p_edge = p_node->m_par_edge; 166 | p_edge->m_rcap -= bottleneck; 167 | p_edge->m_sister->m_rcap += bottleneck; 168 | if(p_edge->m_rcap <= eps){ 169 | p_edge->m_rcap = 0; 170 | mark_orphan(p_node); 171 | } 172 | p_node = p_edge->m_head; 173 | } 174 | p_node->m_rcap += bottleneck; 175 | if(-p_node->m_rcap <= eps){ 176 | p_node->m_rcap = 0; 177 | mark_orphan(p_node); 178 | } 179 | 180 | m_flow += bottleneck; 181 | } 182 | 183 | //////////////////////////////////////////////////////// 184 | template 185 | void graph<_Cap, _DataChunkSize, _PtrChunkSize>::adopt_orphan(node* node_i) 186 | { 187 | bool i_is_sink = node_i->is_sink(); // which tree the orphan node belong, sink (true) or source (false) 188 | node* node_j; 189 | edge* p_edge; 190 | 191 | // try to find a new parent for node i 192 | unsigned int dist; 193 | unsigned int d_max = std::numeric_limits::max(); 194 | unsigned int min_dist = std::numeric_limits::max(); 195 | edge* min_p_edge = 0; // starting from this edge, can backtrack to terminal w/ minimal distance (# of hops) 196 | 197 | for(edge** edge_dptr = node_i->m_out_edges->scan_first(); edge_dptr; edge_dptr = node_i->m_out_edges->scan_next() ){ 198 | p_edge = *edge_dptr; 199 | node_j = p_edge->m_head; 200 | _Cap cap = (i_is_sink) ? p_edge->m_rcap : p_edge->m_sister->m_rcap; 201 | // candidate node j must satisfy: 202 | // 1) the edge between i and j is not saturated, 203 | // 2) it belongs to the same tree as node i, 204 | // 3) it has a parent (not an orphan) 205 | if(cap == 0 || node_j->is_sink() != i_is_sink || node_j->has_parent() == false) continue; 206 | 207 | // node j can become parent for node i only if its originates from the same type of terminal node as node i 208 | // i.e. we can backtrack to terminal node along parent edges without meeting a orphan node. 209 | dist = 0; // distance to terminal node 210 | while(true){ 211 | if(node_j->m_time == m_clock){ // node j was update at the same m_clock --> its origin is already validated 212 | dist += node_j->m_dist; break; 213 | } 214 | dist++; 215 | if(node_j->is_terminal()){ 216 | node_j->m_time = m_clock; node_j->m_dist = 1; break; 217 | } 218 | if(node_j->is_orphan()){ 219 | dist = d_max; break; 220 | } 221 | node_j = node_j->m_par_edge->m_head; 222 | } 223 | 224 | if(dist < d_max){ // node j's origin is valid 225 | if(dist < min_dist){ // we prefer a path such that node j that is closest to the terminal 226 | min_p_edge = p_edge; min_dist = dist; 227 | } 228 | // update time stamps and distance along the path to terminal 229 | for(node_j = p_edge->m_head; node_j->m_time != m_clock; node_j = node_j->m_par_edge->m_head){ 230 | node_j->m_time = m_clock; node_j->m_dist = dist; dist--; 231 | } 232 | } 233 | } 234 | 235 | node_i->m_par_edge = min_p_edge; // update i's parent -- zero: not found 236 | if(min_p_edge != 0){ 237 | node_i->m_time = m_clock; 238 | node_i->m_dist = min_dist+1; 239 | } 240 | else{ 241 | // 1) activate i's neighbors that may claim i as child (positive residual capacity on associated edge) 242 | // 2) node i's children then become orphans 243 | for(edge** edge_dptr = node_i->m_out_edges->scan_first(); edge_dptr; edge_dptr = node_i->m_out_edges->scan_next() ){ 244 | p_edge = *edge_dptr; 245 | node_j = p_edge->m_head; 246 | if(node_j->is_sink() == i_is_sink && node_j->has_parent()){ 247 | _Cap cap = (i_is_sink) ? p_edge->m_rcap : p_edge->m_sister->m_rcap; 248 | if(cap!=0){ 249 | activate(node_j); 250 | } 251 | if(node_j->is_terminal() == false && node_j->is_orphan() == false && node_j->m_par_edge->m_head == node_i){ 252 | mark_orphan(node_j); 253 | } 254 | } 255 | } 256 | } 257 | } 258 | 259 | } // end of namespace 260 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/logismos_chunk_list.hxx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _LOGISMOS_chunk_list_hxx_ 19 | #define _LOGISMOS_chunk_list_hxx_ 20 | 21 | #include // for std::size_t 22 | #include // for std::memset 23 | #include 24 | #include // for testing only 25 | 26 | namespace LOGISMOS{ 27 | 28 | /// \brief A continuous memory chunk used for data storage. 29 | /// 30 | /// It emulates a std::vector<_T> with fixed capacity of _N that can never grow. 31 | /// \note Only a small subset of member functions of std::vector is provided 32 | /// because we assume this class is only directly used by chunk_list class. 33 | /// 34 | /// \author Honghai Zhang 35 | template 36 | class chunk 37 | { 38 | private: 39 | _T m_data[_N]; ///< data buffer (container) with fixed capacity 40 | _T* m_end; ///< pointer to the location after the last valid data elements 41 | 42 | public: 43 | /// \brief Constructor, data buffer is initially filled with zeros. 44 | /// 45 | /// \note Constructor of data type _T is NOT called. 46 | chunk() 47 | { 48 | std::memset(m_data, 0, sizeof(m_data)); 49 | m_end = &(m_data[0]); 50 | } 51 | 52 | // member functions with same names and same or very similar meanings as std::vector 53 | inline _T* begin(){ return &(m_data[0]); } 54 | inline _T* end() { return m_end; } 55 | inline std::size_t size() const{ return m_end - &(m_data[0]); } 56 | inline bool empty() const{ return m_end == &(m_data[0]); } 57 | inline _T& operator[](std::size_t i){ return m_data[i]; } 58 | inline const _T& operator[] (std::size_t i) const{ return m_data[i]; } 59 | 60 | /// \brief Grow the chunk by cnt elements at the end. 61 | /// 62 | /// \return Pointer to the first new element. 63 | /// \note Boundary check is NOT performed. 64 | inline _T* grow(std::size_t cnt=1) 65 | { 66 | _T* ptr = m_end; // the old end is the first new element 67 | m_end += cnt; 68 | return ptr; 69 | } 70 | }; // end of class chunk 71 | 72 | /// \brief A series of chunks 73 | /// 74 | /// This class is specially designed for the use case in which 75 | /// 1) a LARGE number of data elements need to be stored; 76 | /// 2) the number of elements may not be known at construction; 77 | /// 3) the storage can dynamically grow with minimal penalty for performance. 78 | /// Comparing with std::vector 79 | /// 1) grow the chunk_list never requires large blocks of memory to be reallocated and copied; 80 | /// 2) the amount of new memory allocated when growing is fixed instead of always doubling as in std::vector 81 | /// 3) using scan_first() and scan_next() to sequentially access all elements is efficient (should be similar to std::vector); 82 | /// 4) random access using ptr_at() or operator [] is easy and should be good enough 83 | /// but may not be very efficient for sequential access of all elements. 84 | template 85 | class chunk_list 86 | { 87 | typedef chunk<_T, _N> chunk_type; 88 | typedef std::vector list_type; 89 | typedef typename list_type::iterator list_iter_type; 90 | 91 | private: 92 | list_type m_list; ///< the data (chunk) container 93 | std::size_t m_size; ///< actual number of elements of type _T stored, NOT the size of m_list 94 | 95 | _T* m_data_ptr; ///< pointer to the current element of type _T being accessed 96 | list_iter_type m_chunk_iter; ///< iterator of the current chunk being accessed 97 | 98 | public: 99 | /// \brief Constructor 100 | chunk_list() : m_size(0), m_data_ptr(0){ } 101 | 102 | /// \brief Destructor 103 | ~chunk_list(){ clear(); } 104 | 105 | /// \brief Clears all elements in the list and memory allocated. 106 | void clear() 107 | { 108 | m_size = 0; m_data_ptr = 0; 109 | for(list_iter_type iter = m_list.begin(); iter != m_list.end(); ++iter){ delete *iter; } 110 | m_list.clear(); 111 | list_type().swap(m_list); // actually frees memory allocated if list_type is std::vector 112 | } 113 | 114 | /// \brief Returns the total number of elements of type _T in the list. 115 | inline std::size_t size() const{ return m_size; } 116 | 117 | /// \brief Returns number of chunks used by the list 118 | inline std::size_t chunks() const{ return m_list.size(); } 119 | 120 | /// \brief Returns pointer to the beginning of the list 121 | inline _T* begin(){ return m_list.front()->begin(); } 122 | 123 | /// \brief Returns pointer to the end of the list, i.e. pointer to location right after the last element. 124 | inline _T* end(){ return m_list.back()->end(); } 125 | 126 | /// \brief Returns pointer to the ith element (no boundary check). 127 | inline _T* ptr_at(std::size_t i) 128 | { 129 | std::size_t c(0); // which chunk 130 | std::size_t d(i); // index within chunk 131 | while(d >= _N){ c++; d -= _N; } 132 | return m_list[c]->begin()+d; 133 | } 134 | 135 | /// \brief Return reference to the ith element (no boundary check). 136 | inline _T& operator[](std::size_t i) 137 | { 138 | std::size_t c(0); // which chunk 139 | std::size_t d(i); // index within chunk 140 | while(d >= _N){ c++; d -= _N; } 141 | return (*m_list[c])[d]; 142 | } 143 | 144 | /// \brief Returns const reference to the ith element (no boundary check). 145 | inline const _T& operator[](std::size_t i) const 146 | { 147 | std::size_t c(0); // which chunk 148 | std::size_t d(i); // index within chunk 149 | while(d >= _N){ c++; d -= _N; } 150 | return (*m_list[c])[d]; 151 | } 152 | 153 | /// \brief Grow the chunk_list by one elements at the end (allocates a new chunk if needed) and returns pointer to the new element. 154 | inline _T* grow() 155 | { 156 | if(m_list.empty() || m_list.back()->size() == _N){ // list is empty or the last chunk is full 157 | m_list.push_back(new chunk_type()); // create a new chunk 158 | } 159 | m_size++; 160 | return m_list.back()->grow(); 161 | } 162 | 163 | /// brief Add a new element with given value specified in val. 164 | inline void push_back(const _T &val){ *grow() = val; } 165 | 166 | /// \brief Grow the chunk_list by cnt elements, i.e. increase the total number of elements can be stored by cnt. 167 | /// 168 | /// \return index of the first element added, i.e. the total number of elements before the new ones are added. 169 | /// \note If cnt > _N, multiple chunks will be added, thus providing a quick way to allocate memory. 170 | std::size_t grow(std::size_t cnt) 171 | { 172 | std::size_t old_size = m_size; 173 | 174 | if(cnt == 1){ grow(); return old_size; } 175 | if(m_list.empty() || m_list.back()->size() == _N){ // list is empty or the last chunk is full 176 | m_list.push_back(new chunk_type()); // create a new chunk 177 | } 178 | 179 | std::size_t grow_slots = cnt; 180 | std::size_t free_slots = _N - m_list.back()->size(); 181 | if(grow_slots <= free_slots){ // have enough free slots in the last chunk, grow and return 182 | m_list.back()->grow(grow_slots); m_size += grow_slots; return old_size; 183 | } 184 | else{ // not enough space in the last chunk, fill it first 185 | m_list.back()->grow(free_slots); m_size += free_slots; 186 | grow_slots -= free_slots; 187 | } 188 | 189 | std::size_t chunk_cnt = grow_slots / _N; // number of chunk to grow 190 | std::size_t extra_cnt = grow_slots % _N; // number of additional elements to grow that is not a full chunk 191 | for(std::size_t i=0;igrow(_N); m_size += _N; 194 | } 195 | if(extra_cnt > 0){ 196 | m_list.push_back(new chunk_type()); 197 | m_list.back()->grow(extra_cnt); m_size += extra_cnt; 198 | } 199 | return old_size; 200 | } 201 | 202 | /// \brief Returns pointer to the first element to access, 0 if chunk_list is empty 203 | /// 204 | /// Use this to start a loop for all elements. 205 | inline _T* scan_first() 206 | { 207 | if(m_list.empty()) return 0; 208 | m_chunk_iter = m_list.begin(); 209 | m_data_ptr = (*m_chunk_iter)->begin(); 210 | return m_data_ptr; 211 | } 212 | 213 | /// \brief Returns pointer to the ith element, 0 if chunk_list is empty 214 | /// 215 | /// Use this to start a loop starting from the ith element. 216 | inline _T* scan_start(std::size_t i) 217 | { 218 | if(m_list.empty()) return 0; 219 | std::size_t c(0); // which chunk 220 | std::size_t d(i); // index within chunk 221 | while(d >= _N){ c++; d -= _N; } 222 | m_chunk_iter = m_list.begin()+c; 223 | m_data_ptr = (*m_chunk_iter)->begin()+d; 224 | return m_data_ptr; 225 | } 226 | 227 | /// \brief Returns pointer to the next element to access. 228 | /// 229 | /// Use this to continue looping through all elements, 230 | /// will return 0 when reaching the end of the list. 231 | /// \note Must call scan_first() or scan_start(i) before calling this one, will return 0 otherwise. 232 | inline _T* scan_next() 233 | { 234 | if(!m_data_ptr) return 0; 235 | m_data_ptr++; 236 | if(m_data_ptr == (*m_chunk_iter)->end()){ // already pointing to the last element of a chunk 237 | m_chunk_iter++; // move to the next chunk 238 | if(m_chunk_iter == m_list.end()) // reached the last chunk 239 | m_data_ptr = 0; 240 | else 241 | m_data_ptr = (*m_chunk_iter)->begin(); 242 | } 243 | return m_data_ptr; 244 | } 245 | 246 | /// \brief Print elements stored (one chunk a line), for testing purpose only 247 | void print() 248 | { 249 | std::cout<chunks()<<" chunks, "<size()<<" elements"<print(); 252 | } 253 | }; // end of class chunk_list 254 | 255 | } // end of namespace 256 | #endif 257 | -------------------------------------------------------------------------------- /PETTumorSegmentation/MRML/vtkMRMLPETTumorSegmentationParametersNode.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | Portions (c) Copyright University of Iowa All Rights Reserved. 6 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved. 7 | 8 | See COPYRIGHT.txt 9 | or http://www.slicer.org/copyright/copyright.txt for details. 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | ==============================================================================*/ 18 | 19 | #ifndef __vtkMRMLPETTumorSegmentationParametersNode_h 20 | #define __vtkMRMLPETTumorSegmentationParametersNode_h 21 | 22 | // MRML includes 23 | #include "vtkMRML.h" 24 | #include "vtkMRMLNode.h" 25 | #include "vtkMRMLModelNode.h" 26 | #include "vtkMRMLTransformNode.h" 27 | 28 | // VTK includes 29 | #include "vtkStringArray.h" 30 | //#include "vtkImageStash.h" 31 | 32 | // ITK includes 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | // OSF includes 40 | #include "../Logic/itkOSFGraph.h" 41 | 42 | // STL includes 43 | #include 44 | #include 45 | 46 | // for debugging 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | class vtkSlicerSegmentationsModuleLogic; 57 | #include 58 | 59 | #include "vtkSlicerPETTumorSegmentationModuleMRMLExport.h" 60 | 61 | class VTK_SLICER_PETTUMORSEGMENTATION_MODULE_MRML_EXPORT vtkMRMLPETTumorSegmentationParametersNode : public vtkMRMLNode 62 | { 63 | public: 64 | static vtkMRMLPETTumorSegmentationParametersNode *New(); 65 | vtkTypeMacro(vtkMRMLPETTumorSegmentationParametersNode, vtkMRMLNode); 66 | void PrintSelf(ostream& os, vtkIndent indent) override; 67 | 68 | // Description: 69 | // Clear stored processing results 70 | void Clear(); 71 | 72 | // Description: 73 | // Create instance 74 | vtkMRMLNode* CreateNodeInstance() override; 75 | 76 | // Description: 77 | // Set node attributes from name/value pairs 78 | void ReadXMLAttributes( const char** atts) override; 79 | 80 | // Description: 81 | // Write this node's information to a MRML file in XML format. 82 | void WriteXML(ostream& of, int indent) override; 83 | 84 | // Description: 85 | // Copy the node's attributes to this object 86 | void Copy(vtkMRMLNode *node) override; 87 | 88 | // Description: 89 | // Get unique node XML tag name (like Volume, Model) 90 | const char* GetNodeTagName() override {return "PETTumorSegmentationParametersNode"; }; 91 | 92 | vtkGetMacro ( Label, short ); 93 | vtkSetMacro ( Label, short ); 94 | 95 | vtkGetMacro ( PaintOver, bool ); 96 | vtkSetMacro ( PaintOver, bool ); 97 | 98 | vtkGetMacro ( GlobalRefinementOn, bool ); 99 | vtkSetMacro ( GlobalRefinementOn, bool ); 100 | vtkGetMacro ( LocalRefinementOn, bool ); 101 | vtkSetMacro ( LocalRefinementOn, bool ); 102 | bool GetNoRefinementOn() { return !(LocalRefinementOn || GlobalRefinementOn); } 103 | 104 | vtkGetStringMacro ( PETVolumeReference ); 105 | vtkSetStringMacro ( PETVolumeReference ); 106 | 107 | vtkGetStringMacro ( CenterPointIndicatorListReference ); 108 | vtkSetStringMacro ( CenterPointIndicatorListReference ); 109 | 110 | vtkGetStringMacro ( GlobalRefinementIndicatorListReference ); 111 | vtkSetStringMacro ( GlobalRefinementIndicatorListReference ); 112 | 113 | vtkGetStringMacro ( LocalRefinementIndicatorListReference ); 114 | vtkSetStringMacro ( LocalRefinementIndicatorListReference ); 115 | 116 | vtkGetStringMacro ( SegmentationVolumeReference ); 117 | vtkSetStringMacro ( SegmentationVolumeReference ); 118 | 119 | vtkGetStringMacro ( SegmentationReference ); 120 | vtkSetStringMacro ( SegmentationReference ); 121 | 122 | vtkGetStringMacro(SelectedSegmentID); 123 | vtkSetStringMacro(SelectedSegmentID); 124 | 125 | vtkGetMacro ( AssistCentering, bool ); 126 | vtkSetMacro ( AssistCentering, bool ); 127 | 128 | vtkGetMacro ( Splitting, bool ); 129 | vtkSetMacro ( Splitting, bool ); 130 | 131 | vtkGetMacro ( Sealing, bool ); 132 | vtkSetMacro ( Sealing, bool ); 133 | 134 | vtkGetMacro ( DenoiseThreshold, bool ); 135 | vtkSetMacro ( DenoiseThreshold, bool ); 136 | 137 | vtkGetMacro ( LinearCost, bool ); 138 | vtkSetMacro ( LinearCost, bool ); 139 | 140 | vtkGetMacro ( NecroticRegion, bool ); 141 | vtkSetMacro ( NecroticRegion, bool ); 142 | 143 | using LabelImageType = itk::Image; 144 | using LabelMapType = itk::LabelMap< itk::LabelObject< short, 3 > >; 145 | using ScalarImageType = itk::Image; 146 | using IndexType = ScalarImageType::IndexType; 147 | using PointType = ScalarImageType::PointType; 148 | using GraphType = itk::OSFGraph; 149 | using MeshType = itk::Mesh; 150 | using HistogramType = std::vector; 151 | using WatershedPixelType = unsigned long; 152 | using WatershedImageType = itk::Image; 153 | 154 | void SetCenterpoint(PointType index) {Centerpoint = index;}; 155 | PointType GetCenterpoint() {return Centerpoint;}; 156 | float GetCenterpointX() { return Centerpoint[0];}; 157 | float GetCenterpointY() { return Centerpoint[1];}; 158 | float GetCenterpointZ() { return Centerpoint[2];}; 159 | 160 | void SetHistogram(HistogramType hist) {Histogram = hist;}; 161 | const HistogramType& GetHistogram() {return Histogram;}; 162 | 163 | void SetHistogramRange(float range) {HistogramRange = range;}; 164 | float GetHistogramRange() const {return HistogramRange;}; 165 | 166 | void SetHistogramMedian(float value) {HistogramMedian = value;}; 167 | float GetHistogramMedian() const {return HistogramMedian;}; 168 | 169 | void SetCenterpointUptake(float value) {CenterpointUptake = value;}; 170 | float GetCenterpointUptake() {return CenterpointUptake;}; 171 | 172 | void SetThreshold(float threshold) {Threshold = threshold;}; 173 | float GetThreshold() {return Threshold;}; 174 | 175 | void SetOSFGraph(GraphType::Pointer graph) {OSFGraph = graph;}; 176 | GraphType::Pointer GetOSFGraph() {return OSFGraph;}; 177 | 178 | void SetInitialLabelMap(LabelImageType::Pointer labelMap) {InitialLabelMap = labelMap;}; 179 | LabelImageType::Pointer GetInitialLabelMap() {return InitialLabelMap;}; 180 | void ClearInitialLabelMap() {InitialLabelMap = nullptr;}; 181 | 182 | // for debugging 183 | virtual void WriteTXT(const char* filename); 184 | 185 | protected: 186 | 187 | vtkMRMLPETTumorSegmentationParametersNode(); 188 | ~vtkMRMLPETTumorSegmentationParametersNode() override; 189 | 190 | vtkMRMLPETTumorSegmentationParametersNode(const vtkMRMLPETTumorSegmentationParametersNode&); 191 | void operator=(const vtkMRMLPETTumorSegmentationParametersNode&); 192 | 193 | // segmentation parameters 194 | /** Current label being applied. */ 195 | short Label{ 1 }; 196 | 197 | /** Whether or not the new label should overwrite existing labels. */ 198 | bool PaintOver{ false }; 199 | 200 | /** Whether or not global refinement is currently set to be applied when refining. */ 201 | bool GlobalRefinementOn{ true }; 202 | 203 | /** Whether or not local refinement is currently set to be applied when refining. */ 204 | bool LocalRefinementOn{ false }; 205 | 206 | /** MRML node ID string for the PET volume node.*/ 207 | char *PETVolumeReference{ nullptr }; 208 | 209 | /** MRML node ID string for the center point fiducial list node.*/ 210 | char *CenterPointIndicatorListReference{ nullptr }; 211 | 212 | /** MRML node ID string for the global refinement point fiducial list node.*/ 213 | char *GlobalRefinementIndicatorListReference{ nullptr }; 214 | 215 | /** MRML node ID string for the local refinement point fiducial list node.*/ 216 | char *LocalRefinementIndicatorListReference{ nullptr }; 217 | 218 | /** MRML node ID string for the segmentation label volume node.*/ 219 | char *SegmentationVolumeReference{ nullptr }; 220 | 221 | /** MRML node ID string for the segmentation node.*/ 222 | char *SegmentationReference{ nullptr }; 223 | 224 | /** ID string for the segment.*/ 225 | char* SelectedSegmentID{ nullptr }; 226 | 227 | /** Whether or not the center point will be adjusted for the segmentation.*/ 228 | bool AssistCentering{ true }; 229 | 230 | /** Whether or not to apply modified splitting costs and penalties for the segmentation.*/ 231 | bool Splitting{ false }; 232 | 233 | /** Whether or not to seal the segmentation after voxelization.*/ 234 | bool Sealing{ false }; 235 | 236 | /** Whether or not to calculate the threshold for the segmentation based on a median-filtered image.*/ 237 | bool DenoiseThreshold{ false }; 238 | 239 | /** Whether or not to set the low-uptake end of the cost function linearly.*/ 240 | bool LinearCost{ false }; 241 | 242 | /** Whether or not to apply the segmentation in necrotic mode.*/ 243 | bool NecroticRegion{ false }; 244 | 245 | // intermediate processing results of each segmentation refinement step that will stored for undo-redo operations 246 | /** The center point after any recentering.*/ 247 | PointType Centerpoint; 248 | 249 | /** The intial label map before starting a segmentation of the current lesion. */ 250 | LabelImageType::Pointer InitialLabelMap{ nullptr }; 251 | 252 | /** The graph structure with all costs and edges.*/ 253 | GraphType::Pointer OSFGraph{ nullptr }; 254 | 255 | /** The histogram of the region around the center.*/ 256 | HistogramType Histogram; 257 | 258 | /** The range of values for the histogram.*/ 259 | float HistogramRange; 260 | 261 | /** The median value of the histogram.*/ 262 | float HistogramMedian; 263 | 264 | /** The uptake value at the center point, linearly interpolated.*/ 265 | float CenterpointUptake; 266 | 267 | /** The threshold currently in use for cost setting.*/ 268 | float Threshold; 269 | 270 | private: 271 | // for debugging 272 | std::string VolumeInfo(vtkMRMLScalarVolumeNode* volume); 273 | template std::string VolumeInfoITK(typename ITKImageType::Pointer image); 274 | std::string FiducialsInfo(vtkMRMLMarkupsFiducialNode* fiducials); 275 | typename LabelImageType::Pointer ConvertSegmentationToITK(); 276 | template typename ITKImageType::Pointer convert2ITK(vtkSmartPointer vtkVolume); 277 | 278 | }; 279 | 280 | #endif 281 | -------------------------------------------------------------------------------- /SegmentEditorPETTumorSegmentationEffect/AnatomicRegionAndModifier-DICOM-HeadAndNeckCancer.json: -------------------------------------------------------------------------------- 1 | { 2 | "AnatomicContextName": "Anatomic codes - Head and Neck Cancer", 3 | "@schema": "https://raw.githubusercontent.com/qiicr/dcmqi/master/doc/anatomic-context-schema.json#", 4 | "AnatomicCodes": { 5 | "AnatomicRegion": [ 6 | { 7 | "cid": "7601", 8 | "CodingSchemeDesignator": "SRT", 9 | "CodeMeaning": "base of tongue", 10 | "UMLSConceptUID": "C0226958", 11 | "CodeValue": "T-53131", 12 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 13 | "SNOMEDCTConceptID": "7283002" 14 | }, 15 | { 16 | "cid": "7601", 17 | "CodingSchemeDesignator": "SRT", 18 | "CodeMeaning": "buccal mucosa", 19 | "UMLSConceptUID": "C1578559", 20 | "CodeValue": "T-51305", 21 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 22 | "SNOMEDCTConceptID": "16811007" 23 | }, 24 | { 25 | "cid": "7601", 26 | "CodingSchemeDesignator": "SRT", 27 | "CodeMeaning": "floor of mouth", 28 | "UMLSConceptUID": "C0026638", 29 | "CodeValue": "T-51200", 30 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 31 | "SNOMEDCTConceptID": "36360002" 32 | }, 33 | { 34 | "cid": "7601", 35 | "CodingSchemeDesignator": "SRT", 36 | "CodeMeaning": "glottis", 37 | "UMLSConceptUID": "C0017681", 38 | "CodeValue": "T-24440", 39 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 40 | "SNOMEDCTConceptID": "1307006" 41 | }, 42 | { 43 | "cid": "7601", 44 | "CodingSchemeDesignator": "SRT", 45 | "CodeMeaning": "hypopharynx", 46 | "UMLSConceptUID": "C0020629", 47 | "CodeValue": "T-55300", 48 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 49 | "SNOMEDCTConceptID": "81502006" 50 | }, 51 | { 52 | "cid": "7601", 53 | "CodingSchemeDesignator": "SRT", 54 | "CodeMeaning": "larynx", 55 | "UMLSConceptUID": "C0023078", 56 | "CodeValue": "T-24100", 57 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 58 | "SNOMEDCTConceptID": "4596009" 59 | }, 60 | { 61 | "cid": "7601", 62 | "CodingSchemeDesignator": "SRT", 63 | "CodeMeaning": "lingual tonsil", 64 | "UMLSConceptUID": "C0229871", 65 | "CodeValue": "T-C5140", 66 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 67 | "SNOMEDCTConceptID": "2048000" 68 | }, 69 | { 70 | "cid": "7601", 71 | "CodingSchemeDesignator": "SRT", 72 | "CodeMeaning": "lip", 73 | "UMLSConceptUID": "C0023759", 74 | "CodeValue": "T-52000", 75 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 76 | "SNOMEDCTConceptID": "48477009" 77 | }, 78 | { 79 | "cid": "7601", 80 | "CodingSchemeDesignator": "SRT", 81 | "CodeMeaning": "lower alveolar ridge", 82 | "UMLSConceptUID": "C0222755", 83 | "CodeValue": "T-D07CB", 84 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 85 | "SNOMEDCTConceptID": "288546009" 86 | }, 87 | { 88 | "cid": "7601", 89 | "CodingSchemeDesignator": "SRT", 90 | "CodeMeaning": "maxillary sinus", 91 | "UMLSConceptUID": "C0024957", 92 | "CodeValue": "T-22100", 93 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 94 | "SNOMEDCTConceptID": "15924003" 95 | }, 96 | { 97 | "cid": "7601", 98 | "CodingSchemeDesignator": "SRT", 99 | "CodeMeaning": "nasal cavity", 100 | "UMLSConceptUID": "C0027423", 101 | "CodeValue": "T-21301", 102 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 103 | "SNOMEDCTConceptID": "279549004" 104 | }, 105 | { 106 | "cid": "7601", 107 | "CodingSchemeDesignator": "SRT", 108 | "CodeMeaning": "nasopharynx", 109 | "UMLSConceptUID": "C0027442", 110 | "CodeValue": "T-23000", 111 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 112 | "SNOMEDCTConceptID": "71836000" 113 | }, 114 | { 115 | "cid": "7601", 116 | "CodingSchemeDesignator": "SRT", 117 | "CodeMeaning": "oral cavity", 118 | "UMLSConceptUID": "C0226896", 119 | "CodeValue": "T-51004", 120 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 121 | "SNOMEDCTConceptID": "74262004" 122 | }, 123 | { 124 | "cid": "7601", 125 | "CodingSchemeDesignator": "SRT", 126 | "CodeMeaning": "oropharyngeal tonsil (waldeyer's ring)", 127 | "UMLSConceptUID": "C0459892", 128 | "CodeValue": "T-C5000", 129 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 130 | "SNOMEDCTConceptID": "17861009" 131 | }, 132 | { 133 | "cid": "7601", 134 | "CodingSchemeDesignator": "SRT", 135 | "CodeMeaning": "oropharynx", 136 | "UMLSConceptUID": "C0521367", 137 | "CodeValue": "T-55200", 138 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 139 | "SNOMEDCTConceptID": "31389004" 140 | }, 141 | { 142 | "cid": "7601", 143 | "CodingSchemeDesignator": "SRT", 144 | "CodeMeaning": "palatine tonsil", 145 | "UMLSConceptUID": "C0040421", 146 | "CodeValue": "T-C5100", 147 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 148 | "SNOMEDCTConceptID": "75573002" 149 | }, 150 | { 151 | "cid": "7601", 152 | "CodingSchemeDesignator": "SRT", 153 | "CodeMeaning": "palatine uvula", 154 | "UMLSConceptUID": "C0042173", 155 | "CodeValue": "T-51130", 156 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 157 | "SNOMEDCTConceptID": "26140008" 158 | }, 159 | { 160 | "cid": "7601", 161 | "CodingSchemeDesignator": "SRT", 162 | "CodeMeaning": "paranasal sinus", 163 | "UMLSConceptUID": "C0030471", 164 | "CodeValue": "T-22000", 165 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 166 | "SNOMEDCTConceptID": "2095001" 167 | }, 168 | { 169 | "cid": "7601", 170 | "CodingSchemeDesignator": "SRT", 171 | "CodeMeaning": "pharyngeal tonsil (adenoid)", 172 | "UMLSConceptUID": "C0001428", 173 | "CodeValue": "T-C5300", 174 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 175 | "SNOMEDCTConceptID": "55940004" 176 | }, 177 | { 178 | "cid": "7601", 179 | "CodingSchemeDesignator": "SRT", 180 | "CodeMeaning": "pyriform sinus", 181 | "UMLSConceptUID": "C0227170", 182 | "CodeValue": "T-55320", 183 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 184 | "SNOMEDCTConceptID": "6217003" 185 | }, 186 | { 187 | "cid": "7601", 188 | "CodingSchemeDesignator": "SRT", 189 | "CodeMeaning": "retromolar trigone", 190 | "UMLSConceptUID": "C0226920", 191 | "CodeValue": "T-51600", 192 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 193 | "SNOMEDCTConceptID": "85816001" 194 | }, 195 | { 196 | "cid": "7601", 197 | "CodingSchemeDesignator": "SRT", 198 | "CodeMeaning": "salivary gland", 199 | "UMLSConceptUID": "C0036098", 200 | "CodeValue": "T-61007", 201 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 202 | "SNOMEDCTConceptID": "385294005" 203 | }, 204 | { 205 | "cid": "7601", 206 | "CodingSchemeDesignator": "SRT", 207 | "CodeMeaning": "supraglottis", 208 | "UMLSConceptUID": "C0225574", 209 | "CodeValue": "T-24454", 210 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 211 | "SNOMEDCTConceptID": "119255006" 212 | }, 213 | { 214 | "cid": "7601", 215 | "CodingSchemeDesignator": "SRT", 216 | "CodeMeaning": "tongue", 217 | "UMLSConceptUID": "C0040408", 218 | "CodeValue": "T-53000", 219 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 220 | "SNOMEDCTConceptID": "21974007" 221 | }, 222 | { 223 | "cid": "7601", 224 | "CodingSchemeDesignator": "SRT", 225 | "CodeMeaning": "tonsil and adenoid", 226 | "UMLSConceptUID": "C0580788", 227 | "CodeValue": "T-C5001", 228 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 229 | "SNOMEDCTConceptID": "303337002" 230 | }, 231 | { 232 | "cid": "7601", 233 | "CodingSchemeDesignator": "SRT", 234 | "CodeMeaning": "tubal tonsil", 235 | "UMLSConceptUID": "C0229883", 236 | "CodeValue": "T-C5330", 237 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 238 | "SNOMEDCTConceptID": "21058000" 239 | }, 240 | { 241 | "cid": "7601", 242 | "CodingSchemeDesignator": "UMLS", 243 | "CodeMeaning": "unknown primary neoplasia site", 244 | "UMLSConceptUID": "C0221297", 245 | "CodeValue": "C0221297", 246 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 247 | "SNOMEDCTConceptID": "" 248 | }, 249 | { 250 | "cid": "7601", 251 | "CodingSchemeDesignator": "SRT", 252 | "CodeMeaning": "uvula", 253 | "UMLSConceptUID": "C0042173", 254 | "CodeValue": "T-51130", 255 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 256 | "SNOMEDCTConceptID": "26140008" 257 | }, 258 | { 259 | "cid": "4030,7154", 260 | "CodingSchemeDesignator": "SRT", 261 | "CodeMeaning": "Liver", 262 | "UMLSConceptUID": "C0023884", 263 | "CodeValue": "T-62000", 264 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 265 | "SNOMEDCTConceptID": "10200004" 266 | }, 267 | { 268 | "cid": "4030", 269 | "CodingSchemeDesignator": "SRT", 270 | "CodeMeaning": "Cerebellum", 271 | "UMLSConceptUID": "C0007765", 272 | "CodeValue": "T-A6000", 273 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 274 | "SNOMEDCTConceptID": "113305005" 275 | }, 276 | { 277 | "cid": "3010,4030,6117", 278 | "CodingSchemeDesignator": "SRT", 279 | "CodeMeaning": "Aortic arch", 280 | "UMLSConceptUID": "C0003489", 281 | "CodeValue": "T-42300", 282 | "contextGroupName": "Head and Neck Cancer Anatomic Sites", 283 | "SNOMEDCTConceptID": "57034009" 284 | }, 285 | { 286 | "cid": "7600", 287 | "CodingSchemeDesignator": "SRT", 288 | "CodeMeaning": "lymph node of head and neck", 289 | "CodeValue": "T-C4004", 290 | "SNOMEDCTConceptID": "312501005", 291 | "UMLSConceptUID": "C0729853" 292 | } 293 | ] 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | 2 | For more information, please see: 3 | 4 | http://www.slicer.org 5 | 6 | The 3D Slicer license below is a BSD style license, with extensions 7 | to cover contributions and other issues specific to 3D Slicer. 8 | 9 | 10 | 3D Slicer Contribution and Software License Agreement ("Agreement") 11 | Version 1.0 (December 20, 2005) 12 | 13 | This Agreement covers contributions to and downloads from the 3D 14 | Slicer project ("Slicer") maintained by The Brigham and Women's 15 | Hospital, Inc. ("Brigham"). Part A of this Agreement applies to 16 | contributions of software and/or data to Slicer (including making 17 | revisions of or additions to code and/or data already in Slicer). Part 18 | B of this Agreement applies to downloads of software and/or data from 19 | Slicer. Part C of this Agreement applies to all transactions with 20 | Slicer. If you distribute Software (as defined below) downloaded from 21 | Slicer, all of the paragraphs of Part B of this Agreement must be 22 | included with and apply to such Software. 23 | 24 | Your contribution of software and/or data to Slicer (including prior 25 | to the date of the first publication of this Agreement, each a 26 | "Contribution") and/or downloading, copying, modifying, displaying, 27 | distributing or use of any software and/or data from Slicer 28 | (collectively, the "Software") constitutes acceptance of all of the 29 | terms and conditions of this Agreement. If you do not agree to such 30 | terms and conditions, you have no right to contribute your 31 | Contribution, or to download, copy, modify, display, distribute or use 32 | the Software. 33 | 34 | PART A. CONTRIBUTION AGREEMENT - License to Brigham with Right to 35 | Sublicense ("Contribution Agreement"). 36 | 37 | 1. As used in this Contribution Agreement, "you" means the individual 38 | contributing the Contribution to Slicer and the institution or 39 | entity which employs or is otherwise affiliated with such 40 | individual in connection with such Contribution. 41 | 42 | 2. This Contribution Agreement applies to all Contributions made to 43 | Slicer, including without limitation Contributions made prior to 44 | the date of first publication of this Agreement. If at any time you 45 | make a Contribution to Slicer, you represent that (i) you are 46 | legally authorized and entitled to make such Contribution and to 47 | grant all licenses granted in this Contribution Agreement with 48 | respect to such Contribution; (ii) if your Contribution includes 49 | any patient data, all such data is de-identified in accordance with 50 | U.S. confidentiality and security laws and requirements, including 51 | but not limited to the Health Insurance Portability and 52 | Accountability Act (HIPAA) and its regulations, and your disclosure 53 | of such data for the purposes contemplated by this Agreement is 54 | properly authorized and in compliance with all applicable laws and 55 | regulations; and (iii) you have preserved in the Contribution all 56 | applicable attributions, copyright notices and licenses for any 57 | third party software or data included in the Contribution. 58 | 59 | 3. Except for the licenses granted in this Agreement, you reserve all 60 | right, title and interest in your Contribution. 61 | 62 | 4. You hereby grant to Brigham, with the right to sublicense, a 63 | perpetual, worldwide, non-exclusive, no charge, royalty-free, 64 | irrevocable license to use, reproduce, make derivative works of, 65 | display and distribute the Contribution. If your Contribution is 66 | protected by patent, you hereby grant to Brigham, with the right to 67 | sublicense, a perpetual, worldwide, non-exclusive, no-charge, 68 | royalty-free, irrevocable license under your interest in patent 69 | rights covering the Contribution, to make, have made, use, sell and 70 | otherwise transfer your Contribution, alone or in combination with 71 | any other code. 72 | 73 | 5. You acknowledge and agree that Brigham may incorporate your 74 | Contribution into Slicer and may make Slicer available to members 75 | of the public on an open source basis under terms substantially in 76 | accordance with the Software License set forth in Part B of this 77 | Agreement. You further acknowledge and agree that Brigham shall 78 | have no liability arising in connection with claims resulting from 79 | your breach of any of the terms of this Agreement. 80 | 81 | 6. YOU WARRANT THAT TO THE BEST OF YOUR KNOWLEDGE YOUR CONTRIBUTION 82 | DOES NOT CONTAIN ANY CODE THAT REQURES OR PRESCRIBES AN "OPEN 83 | SOURCE LICENSE" FOR DERIVATIVE WORKS (by way of non-limiting 84 | example, the GNU General Public License or other so-called 85 | "reciprocal" license that requires any derived work to be licensed 86 | under the GNU General Public License or other "open source 87 | license"). 88 | 89 | PART B. DOWNLOADING AGREEMENT - License from Brigham with Right to 90 | Sublicense ("Software License"). 91 | 92 | 1. As used in this Software License, "you" means the individual 93 | downloading and/or using, reproducing, modifying, displaying and/or 94 | distributing the Software and the institution or entity which 95 | employs or is otherwise affiliated with such individual in 96 | connection therewith. The Brigham and Women?s Hospital, 97 | Inc. ("Brigham") hereby grants you, with right to sublicense, with 98 | respect to Brigham's rights in the software, and data, if any, 99 | which is the subject of this Software License (collectively, the 100 | "Software"), a royalty-free, non-exclusive license to use, 101 | reproduce, make derivative works of, display and distribute the 102 | Software, provided that: 103 | 104 | (a) you accept and adhere to all of the terms and conditions of this 105 | Software License; 106 | 107 | (b) in connection with any copy of or sublicense of all or any portion 108 | of the Software, all of the terms and conditions in this Software 109 | License shall appear in and shall apply to such copy and such 110 | sublicense, including without limitation all source and executable 111 | forms and on any user documentation, prefaced with the following 112 | words: "All or portions of this licensed product (such portions are 113 | the "Software") have been obtained under license from The Brigham and 114 | Women's Hospital, Inc. and are subject to the following terms and 115 | conditions:" 116 | 117 | (c) you preserve and maintain all applicable attributions, copyright 118 | notices and licenses included in or applicable to the Software; 119 | 120 | (d) modified versions of the Software must be clearly identified and 121 | marked as such, and must not be misrepresented as being the original 122 | Software; and 123 | 124 | (e) you consider making, but are under no obligation to make, the 125 | source code of any of your modifications to the Software freely 126 | available to others on an open source basis. 127 | 128 | 2. The license granted in this Software License includes without 129 | limitation the right to (i) incorporate the Software into 130 | proprietary programs (subject to any restrictions applicable to 131 | such programs), (ii) add your own copyright statement to your 132 | modifications of the Software, and (iii) provide additional or 133 | different license terms and conditions in your sublicenses of 134 | modifications of the Software; provided that in each case your use, 135 | reproduction or distribution of such modifications otherwise 136 | complies with the conditions stated in this Software License. 137 | 138 | 3. This Software License does not grant any rights with respect to 139 | third party software, except those rights that Brigham has been 140 | authorized by a third party to grant to you, and accordingly you 141 | are solely responsible for (i) obtaining any permissions from third 142 | parties that you need to use, reproduce, make derivative works of, 143 | display and distribute the Software, and (ii) informing your 144 | sublicensees, including without limitation your end-users, of their 145 | obligations to secure any such required permissions. 146 | 147 | 4. The Software has been designed for research purposes only and has 148 | not been reviewed or approved by the Food and Drug Administration 149 | or by any other agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL 150 | APPLICATIONS ARE NEITHER RECOMMENDED NOR ADVISED. Any 151 | commercialization of the Software is at the sole risk of the party 152 | or parties engaged in such commercialization. You further agree to 153 | use, reproduce, make derivative works of, display and distribute 154 | the Software in compliance with all applicable governmental laws, 155 | regulations and orders, including without limitation those relating 156 | to export and import control. 157 | 158 | 5. The Software is provided "AS IS" and neither Brigham nor any 159 | contributor to the software (each a "Contributor") shall have any 160 | obligation to provide maintenance, support, updates, enhancements 161 | or modifications thereto. BRIGHAM AND ALL CONTRIBUTORS SPECIFICALLY 162 | DISCLAIM ALL EXPRESS AND IMPLIED WARRANTIES OF ANY KIND INCLUDING, 163 | BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR 164 | A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 165 | BRIGHAM OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR DIRECT, 166 | INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES 167 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY 168 | RELATED TO THE SOFTWARE, EVEN IF BRIGHAM OR ANY CONTRIBUTOR HAS 169 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM 170 | EXTENT NOT PROHIBITED BY LAW OR REGULATION, YOU FURTHER ASSUME ALL 171 | LIABILITY FOR YOUR USE, REPRODUCTION, MAKING OF DERIVATIVE WORKS, 172 | DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE AND AGREE TO 173 | INDEMNIFY AND HOLD HARMLESS BRIGHAM AND ALL CONTRIBUTORS FROM AND 174 | AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS 175 | ARISING THEREFROM. 176 | 177 | 6. None of the names, logos or trademarks of Brigham or any of 178 | Brigham's affiliates or any of the Contributors, or any funding 179 | agency, may be used to endorse or promote products produced in 180 | whole or in part by operation of the Software or derived from or 181 | based on the Software without specific prior written permission 182 | from the applicable party. 183 | 184 | 7. Any use, reproduction or distribution of the Software which is not 185 | in accordance with this Software License shall automatically revoke 186 | all rights granted to you under this Software License and render 187 | Paragraphs 1 and 2 of this Software License null and void. 188 | 189 | 8. This Software License does not grant any rights in or to any 190 | intellectual property owned by Brigham or any Contributor except 191 | those rights expressly granted hereunder. 192 | 193 | PART C. MISCELLANEOUS 194 | 195 | This Agreement shall be governed by and construed in accordance with 196 | the laws of The Commonwealth of Massachusetts without regard to 197 | principles of conflicts of law. This Agreement shall supercede and 198 | replace any license terms that you may have agreed to previously with 199 | respect to Slicer. 200 | -------------------------------------------------------------------------------- /Testing/SegmentEditorPETTumorSegmentationEffectSelfTest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | import vtk, qt, ctk, slicer, logging 4 | from DICOMLib import DICOMUtils 5 | from SegmentStatistics import SegmentStatisticsLogic 6 | import vtkSegmentationCorePython as vtkSegmentationCore 7 | from slicer.ScriptedLoadableModule import * 8 | 9 | # 10 | # SegmentEditorPETTumorSegmentationEffectSelfTest 11 | # 12 | 13 | class SegmentEditorPETTumorSegmentationEffectSelfTest(ScriptedLoadableModule): 14 | def __init__(self, parent): 15 | ScriptedLoadableModule.__init__(self, parent) 16 | self.parent.title = "SegmentEditorPETTumorSegmentationEffectSelfTest" 17 | self.parent.categories = ["Testing.TestCases"] 18 | self.parent.dependencies = ["SegmentStatistics"] 19 | self.parent.contributors = ["Christian Bauer (University of Iowa)"] 20 | self.parent.helpText = """This is a self test for SegmentEditorPETTumorSegmentationEffect.""" 21 | parent.acknowledgementText = """This work was partially funded by NIH grants U01-CA140206 and U24-CA180918.""" 22 | 23 | # 24 | # SegmentEditorPETTumorSegmentationEffectSelfTestWidget 25 | # 26 | 27 | class SegmentEditorPETTumorSegmentationEffectSelfTestWidget(ScriptedLoadableModuleWidget): 28 | """Uses ScriptedLoadableModuleWidget base class, available at: 29 | https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py 30 | """ 31 | def setup(self): 32 | ScriptedLoadableModuleWidget.setup(self) 33 | # Instantiate and connect widgets ... 34 | 35 | # Collapsible button 36 | testsCollapsibleButton = ctk.ctkCollapsibleButton() 37 | testsCollapsibleButton.text = "SegmentEditorPETTumorSegmentationEffect Tests" 38 | self.layout.addWidget(testsCollapsibleButton) 39 | 40 | # Layout within the collapsible button 41 | collapsibleButtonLayout = qt.QFormLayout(testsCollapsibleButton) 42 | 43 | self.loadTestDataButton = qt.QPushButton("Download and load test data") 44 | self.loadTestDataButton.connect('clicked(bool)', self.onLoadTestData) 45 | collapsibleButtonLayout.addWidget(self.loadTestDataButton) 46 | 47 | # Add vertical spacer 48 | self.layout.addStretch(1) 49 | 50 | def onLoadTestData(self): 51 | tester = SegmentEditorPETTumorSegmentationEffectSelfTestTest() 52 | tester.loadTestData() 53 | 54 | # 55 | # SegmentEditorPETTumorSegmentationEffectSelfTestLogic 56 | # 57 | 58 | class SegmentEditorPETTumorSegmentationEffectSelfTestLogic(ScriptedLoadableModuleLogic): 59 | """This class should implement all the actual 60 | computation done by your module. The interface 61 | should be such that other python code can import 62 | this class and make use of the functionality without 63 | requiring an instance of the Widget 64 | """ 65 | 66 | 67 | class SegmentEditorPETTumorSegmentationEffectSelfTestTest(ScriptedLoadableModuleTest): 68 | """ 69 | This is the test case for your scripted module. 70 | Uses ScriptedLoadableModuleTest base class, available at: 71 | https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py 72 | """ 73 | 74 | def runTest(self): 75 | """Run as few or as many tests as needed here. 76 | """ 77 | self.setUp() 78 | self.test_SegmentEditorEffect() 79 | self.tearDown() 80 | 81 | def setUp(self): 82 | """ Open temporary DICOM database 83 | """ 84 | slicer.mrmlScene.Clear(0) 85 | self.delayMs = 700 86 | self.tempDataDir = os.path.join(slicer.app.temporaryPath,'PETTest') 87 | self.tempDicomDatabaseDir = os.path.join(slicer.app.temporaryPath,'PETTestDicom') 88 | 89 | def doCleanups(self): 90 | """ cleanup temporary data in case an exception occurs 91 | """ 92 | self.tearDown() 93 | 94 | def tearDown(self): 95 | """ Close temporary DICOM database and remove temporary data 96 | """ 97 | try: 98 | import shutil 99 | if os.path.exists(self.tempDataDir): 100 | shutil.rmtree(self.tempDataDir) 101 | except Exception as e: 102 | import traceback 103 | traceback.print_exc() 104 | self.delayDisplay('Test caused exception!\n' + str(e),self.delayMs*2) 105 | 106 | def loadTestData(self): 107 | #download data and add to dicom database 108 | zipFileUrl = 'https://github.com/QIICR/PETTumorSegmentation/releases/download/4.10.2/QIN-HEADNECK-01-0139-PET.zip' 109 | zipFilePath = self.tempDataDir+'/dicom.zip' 110 | zipFileData = self.tempDataDir+'/dicom' 111 | expectedNumOfFiles = 545 112 | if not os.access(self.tempDataDir, os.F_OK): 113 | os.mkdir(self.tempDataDir) 114 | if not os.access(zipFileData, os.F_OK): 115 | os.mkdir(zipFileData) 116 | slicer.util.downloadAndExtractArchive( zipFileUrl, zipFilePath, zipFileData, expectedNumOfFiles) 117 | DICOMUtils.importDicom(zipFileData) 118 | 119 | # load dataset 120 | dicomFiles = slicer.util.getFilesInDirectory(zipFileData) 121 | loadablesByPlugin, loadEnabled = DICOMUtils.getLoadablesFromFileLists([dicomFiles],['DICOMScalarVolumePlugin']) 122 | loadedNodeIDs = DICOMUtils.loadLoadables(loadablesByPlugin) 123 | imageNode = slicer.mrmlScene.GetNodeByID(loadedNodeIDs[0]) 124 | imageNode.SetSpacing(3.3940266832237, 3.3940266832237, 2.02490234375) # mimic spacing as produced by Slicer 4.10 for which the test was originally developed 125 | imageNode.SetOrigin(285.367523193359375,494.58682250976556816,-1873.3819580078125) # mimic origin as produced by Slicer 4.10 for which the test was originally developed 126 | 127 | # apply the SUVbw conversion factor and set units and quantity 128 | suvNormalizationFactor = 0.00040166400000000007 129 | quantity = slicer.vtkCodedEntry() 130 | quantity.SetFromString('CodeValue:126400|CodingSchemeDesignator:DCM|CodeMeaning:Standardized Uptake Value') 131 | units = slicer.vtkCodedEntry() 132 | units.SetFromString('CodeValue:{SUVbw}g/ml|CodingSchemeDesignator:UCUM|CodeMeaning:Standardized Uptake Value body weight') 133 | multiplier = vtk.vtkImageMathematics() 134 | multiplier.SetOperationToMultiplyByK() 135 | multiplier.SetConstantK(suvNormalizationFactor) 136 | multiplier.SetInput1Data(imageNode.GetImageData()) 137 | multiplier.Update() 138 | imageNode.GetImageData().DeepCopy(multiplier.GetOutput()) 139 | imageNode.GetVolumeDisplayNode().SetWindowLevel(6,3) 140 | imageNode.GetVolumeDisplayNode().SetAndObserveColorNodeID('vtkMRMLColorTableNodeInvertedGrey') 141 | imageNode.SetVoxelValueQuantity(quantity) 142 | imageNode.SetVoxelValueUnits(units) 143 | 144 | return imageNode 145 | 146 | def test_SegmentEditorEffect(self): 147 | 148 | self.assertIsNotNone( slicer.vtkSlicerPETTumorSegmentationLogic ) 149 | with DICOMUtils.TemporaryDICOMDatabase(self.tempDicomDatabaseDir) as db: 150 | self.assertTrue(db.isOpen) 151 | self.assertEqual(slicer.dicomDatabase, db) 152 | 153 | self.delayDisplay('Loading PET DICOM dataset (including download if necessary)') 154 | petNode = self.loadTestData() 155 | self.delayDisplay('Switching to Segment Editor') 156 | slicer.util.mainWindow().moduleSelector().selectModule('SegmentEditor') 157 | widget = slicer.modules.SegmentEditorWidget 158 | editor = widget.editor 159 | params = widget.parameterSetNode 160 | seg = widget.editor.segmentationNode() 161 | 162 | self.delayDisplay('Adding emtpy segment') 163 | # add segment similar to onAddSegment: https://github.com/Slicer/Slicer/blob/28ea2ebef031788d706a3085a46fac41d0017c05/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.cxx#L1894 164 | editor.saveStateForUndo() 165 | addedSegmentID = seg.GetSegmentation().AddEmptySegment() 166 | editor.setCurrentSegmentID(addedSegmentID) 167 | 168 | # switch to PET tumor segmentation effect 169 | self.delayDisplay('Activating PET Tumor Segmentation effect') 170 | editor.setActiveEffectByName('PET Tumor Segmentation') 171 | effect = editor.activeEffect() 172 | self.assertIsNotNone(effect) 173 | 174 | # one-click segmentation 175 | self.delayDisplay('Applying one-click segmentation') 176 | effect.self().onApplyMouseClick([41.3,220.1,-980.2]) 177 | self.assertEqual(self.getSignature(seg),2890720391) 178 | 179 | # global refinement 180 | self.delayDisplay('Applying global refinement') 181 | effect.self().globalRefinementRadioButton.click() 182 | effect.self().onApplyMouseClick([40.1,264.2,-969.2]) 183 | self.assertEqual(self.getSignature(seg),3700505133) 184 | 185 | # local refinement 186 | self.delayDisplay('Applying local refinement') 187 | effect.self().localRefinementRadioButton.click() 188 | effect.self().onApplyMouseClick([40.1,258.1,-1025.1]) 189 | self.assertEqual(self.getSignature(seg),3550788737) 190 | 191 | # undo with local refinement 192 | self.delayDisplay('Testing undo with local refinement') 193 | editor.undo() 194 | self.assertEqual(self.getSignature(seg),3700505133) 195 | effect.self().onApplyMouseClick([40.1,234.2, 934.7]) 196 | self.assertEqual(self.getSignature(seg),3257504375) 197 | 198 | # check that editor undo/redo history works and go back to initial segmentation before refinement 199 | self.delayDisplay('Testing segment editor undo/redo history') 200 | editor.undo() 201 | self.assertEqual(self.getSignature(seg),3700505133) 202 | editor.undo() 203 | self.assertEqual(self.getSignature(seg),2890720391) 204 | editor.redo() 205 | self.assertEqual(self.getSignature(seg),3700505133) 206 | editor.undo() 207 | self.assertEqual(self.getSignature(seg),2890720391) 208 | 209 | #use splitting option 210 | self.delayDisplay('Applying splitting option') 211 | effect.self().splittingCheckBox.checked = True 212 | effect.self().onApplyParameters() 213 | self.assertEqual(self.getSignature(seg),4476495726) 214 | 215 | # add second segment 216 | self.delayDisplay('Adding second segment') 217 | editor.saveStateForUndo() 218 | addedSegmentID = seg.GetSegmentation().AddEmptySegment() 219 | editor.setCurrentSegmentID(addedSegmentID) 220 | 221 | # one-click segmentation 222 | self.delayDisplay('Applying one-click segmentation') 223 | effect.self().onApplyMouseClick([41.3,229.1,-952.5]) 224 | effect.self().onApplyParameters() 225 | self.assertEqual(self.getSignature(seg),5717391304) 226 | 227 | # disable assist centering 228 | self.delayDisplay('Applying disabled assist centering option') 229 | effect.self().assistCenteringCheckBox.checked = False 230 | effect.self().onApplyParameters() 231 | self.assertEqual(self.getSignature(seg),5802341598) 232 | 233 | # sealing centering 234 | self.delayDisplay('Applying sealing option') 235 | effect.self().sealingCheckBox.checked = True 236 | effect.self().onApplyParameters() 237 | self.assertEqual(self.getSignature(seg),5864325069) 238 | 239 | # overwriting 240 | self.delayDisplay('Applying overwriting option') 241 | effect.self().allowOverwritingCheckBox.checked = True 242 | effect.self().onApplyParameters() 243 | self.assertEqual(self.getSignature(seg),7592592593) 244 | 245 | editor.undo() 246 | self.assertEqual(self.getSignature(seg),5864325069) 247 | 248 | self.delayDisplay('Test passed!') 249 | 250 | def getSignature(self, seg): 251 | if not 'labelmap' in self.__dict__ or not self.labelmap: 252 | self.labelmap = slicer.vtkMRMLLabelMapVolumeNode() 253 | slicer.mrmlScene.AddNode(self.labelmap) 254 | slicer.modules.segmentations.logic().ExportAllSegmentsToLabelmapNode(seg, self.labelmap) 255 | stat = vtk.vtkImageAccumulate() 256 | stat.SetInputData(self.labelmap.GetImageData()) 257 | stat.Update() 258 | return int(round(stat.GetMean()[0]*1e10)) 259 | -------------------------------------------------------------------------------- /PETTumorSegmentation/Logic/logismos_graph.hxx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: PETTumorSegmentation 4 | 5 | (c) Copyright University of Iowa All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef _LOGISMOS_graph_hxx_ 19 | #define _LOGISMOS_graph_hxx_ 20 | 21 | #include "logismos_chunk_list.hxx" 22 | #include 23 | #include 24 | #include 25 | 26 | namespace LOGISMOS{ 27 | 28 | /// \brief Data structure for graph designed for BK's maxflow algorithm. 29 | /// 30 | /// _DataChunkSize is the size of a chunk (see chunk_list.hxx) used to store 31 | /// graph nodes or edges, using large value for large graph can improve the performance. 32 | /// _PtrChunkSize is the size of a chunk used to store pointers to edges associated with 33 | /// a node, should be similar to the number of such edges. 34 | /// 35 | /// \author Honghai Zhang 36 | template 37 | class graph 38 | { 39 | struct node; 40 | struct edge; 41 | 42 | typedef chunk_list node_cont_type; ///< for node container 43 | typedef chunk_list edge_cont_type; ///< for edge container 44 | typedef std::deque node_p_queue_type; ///< for FIFO of node pointers 45 | typedef chunk_list edge_p_cont_type; ///< for 'array' of edge pointers 46 | 47 | /// \brief Data structure for a graph node 48 | struct node{ 49 | edge_p_cont_type* m_out_edges; ///< outgoing edges, tail=this node 50 | edge* m_par_edge; ///< parent edge in the search tree. 0: no parent, 1: terminal, 2: orphan 51 | 52 | _Cap m_rcap; ///< residual capacity, positive for source->node, negative for node->sink 53 | unsigned int m_dist; ///< distance (number of edges) to terminal node (source or sink) 54 | unsigned int m_time; ///< a time stamp indicates when m_dist is modified 55 | unsigned char m_tag; ///< several bitwise tags, [na, na, na, na, changed, marked, active, sink] 56 | 57 | /// \brief Constructor, probably will not be called by other member functions of the graph class 58 | node() : m_par_edge(0), m_rcap(0), m_dist(0), m_time(0), m_tag(0) 59 | { 60 | m_out_edges = new edge_p_cont_type(); 61 | } 62 | 63 | /// \brief Destructor. 64 | ~node(){ delete m_out_edges; m_out_edges = 0;} 65 | 66 | // quick ways to determine and set special status of the node and its parent edge. 67 | 68 | inline bool is_changed(){ return (m_tag&0x08)!=0; } 69 | inline bool is_marked(){ return (m_tag&0x04)!=0; } 70 | inline bool is_active(){ return (m_tag&0x02)!=0; } 71 | inline bool is_sink(){ return (m_tag&0x01)!=0; } 72 | 73 | inline bool has_parent(){ return m_par_edge!=0; } 74 | inline bool is_terminal(){ return m_par_edge==reinterpret_cast(1); } 75 | inline bool is_orphan(){ return m_par_edge==reinterpret_cast(2); } 76 | 77 | inline void set_changed(bool v){ m_tag = (v) ? (m_tag | 0x08) : (m_tag & ~0x08); } 78 | inline void set_marked(bool v){ m_tag = (v) ? (m_tag | 0x04) : (m_tag & ~0x04); } 79 | inline void set_active(bool v){ m_tag = (v) ? (m_tag | 0x02) : (m_tag & ~0x02); } 80 | inline void set_sink(bool v){ m_tag = (v) ? (m_tag | 0x01) : (m_tag & ~0x01); } 81 | 82 | inline void set_terminal(){ m_par_edge=reinterpret_cast(1); } 83 | inline void set_orphan(){ m_par_edge=reinterpret_cast(2); } 84 | }; 85 | 86 | /// brief Data structure for a directed edge 87 | /// 88 | /// The directed edge starts from a tail node and ends at a head node with a given capacity. 89 | struct edge{ 90 | node* m_head; ///< node the edge points to 91 | _Cap m_rcap; ///< residual capacity of the edge 92 | edge* m_sister; ///< corresponding edge with opposite direction in the residual graph 93 | }; 94 | 95 | private: 96 | node_cont_type m_nodes; ///< all the graph nodes 97 | edge_cont_type m_edges; ///< all the graph edges 98 | node_p_queue_type m_active_nodes; ///< a queue (FIFO) for active nodes 99 | node_p_queue_type m_orphan_nodes; ///< a queue (FIFO) for orphan nodes 100 | unsigned int m_clock; ///< a global clock provides time stamp for all nodes 101 | _Cap m_flow; ///< total flow in the graph 102 | 103 | /// \brief Set node as active and add it to active node queue. 104 | inline void activate(node* p_node) 105 | { 106 | assert(p_node); 107 | if(p_node->is_active() == false){ 108 | p_node->set_active(true); 109 | m_active_nodes.push_back(p_node); 110 | } 111 | } 112 | 113 | /// \brief Mark given node as orphan and add it to the orphan queue. 114 | inline void mark_orphan(node* p_node) 115 | { 116 | if(p_node->is_orphan() == false){ 117 | p_node->set_orphan(); 118 | m_orphan_nodes.push_back(p_node); 119 | } 120 | } 121 | 122 | ///////////////////////////////////////////////////////// 123 | 124 | /// \brief Grow search trees from the given active node. 125 | /// 126 | /// \return The edge that connects source and sink search trees, zero if not found. 127 | edge* grow_active_node(node* node_i); 128 | 129 | /// \brief Augment the path found by grow_active_node(). 130 | void augment_path(edge* mid_edge); 131 | 132 | /// \brief Adopt the orphan node. 133 | void adopt_orphan(node* node_i); 134 | 135 | ///////////////////////////////////////////////////////// 136 | 137 | public: 138 | 139 | /// \brief Constructor. Create a empty graph 140 | graph() : m_clock(0), m_flow(0){ } 141 | 142 | /// \brief Destructor. 143 | ~graph(){ 144 | m_active_nodes.clear(); m_orphan_nodes.clear(); 145 | m_nodes.clear(); m_edges.clear(); 146 | } 147 | 148 | /// \brief Add one nodes to the graph and returns the index of the node added. 149 | inline std::size_t add_node() 150 | { 151 | std::size_t offset = m_nodes.size(); 152 | node* p_node = m_nodes.grow(); 153 | // initialize the new node since m_nodes.grow() will not call the constructor of node 154 | p_node->m_out_edges = new edge_p_cont_type(); 155 | return offset; 156 | } 157 | 158 | /// \brief Add fixed number (cnt) of nodes to the graph and returns the index of the first node added. 159 | /// 160 | /// If cnt is larger than one, this is faster than calling add_node() cnt times. 161 | /// For LOGISMOS graph with same number nodes per column, we only need to call this function once to add all nodes. 162 | /// If the graph has varying number of nodes per column, call this function for each column is better since it returns 163 | /// the index of the first node in the new column added. 164 | inline std::size_t add_nodes(std::size_t cnt) 165 | { 166 | if(cnt == 1) return add_node(); 167 | std::size_t offset=m_nodes.size(); 168 | m_nodes.grow(cnt); 169 | std::size_t i(0); 170 | for(node* p_node = m_nodes.scan_start(offset); p_node; p_node = m_nodes.scan_next()){ 171 | // initialize the new node since m_nodes.grow() will not call the constructor of node 172 | p_node->m_out_edges = new edge_p_cont_type(); 173 | i++; 174 | } 175 | return offset; 176 | } 177 | 178 | /// \brief Get total number of nodes in the graph. 179 | inline std::size_t get_node_cnt(){ return m_nodes.size(); } 180 | 181 | /// \brief Add NEW terminal edges 'source->i' and 'i->sink' with given capacities. 182 | /// 183 | /// \param s_cap capacity for edge source->i. 184 | /// \param t_cap capacity for edge i->sink. 185 | /// \return true if success, false otherwise. 186 | /// \note If this function is called multiple times, only the first time will has real effect and returns true. 187 | /// \note There are no REAL terminal edges in the graph. They manifest as residual capacities of nodes. 188 | inline bool add_st_edge(std::size_t i, _Cap s_cap, _Cap t_cap) 189 | { 190 | assert(i=0); 192 | assert(t_cap>=0); 193 | 194 | node* p_node = m_nodes.ptr_at(i); 195 | p_node->m_time = 0; 196 | if(p_node->is_active() == false){ 197 | p_node->m_rcap = s_cap - t_cap; 198 | m_flow += (s_cap < t_cap) ? s_cap : t_cap; 199 | if(s_cap != t_cap){ 200 | p_node->set_sink(p_node->m_rcap < 0); 201 | p_node->set_terminal(); 202 | p_node->m_dist = 1; 203 | p_node->set_active(true); 204 | } 205 | else{ 206 | p_node->m_par_edge = 0; // just make sure 207 | } 208 | return true; 209 | } 210 | return false; 211 | } 212 | 213 | /// \brief Add a NEW non-terminal edge from node i to node j. 214 | /// 215 | /// \param fwd_cap non-negative capacity from i to j. 216 | /// \param rev_cap non-negative capacity from j to i. 217 | /// \return the index of the new edge, i.e. number of edges before the new one is added. 218 | /// When used for adding intra-column edges which often have infinite capacity, 219 | /// the user need to provide proper 'infinity' value for cap. 220 | /// \note This function ALWAYS add a new edge (i,j) to the graph even if edge (i,j) already exists. 221 | /// The user is responsible for using this function properly. 222 | inline std::size_t add_edge(std::size_t i, std::size_t j, _Cap fwd_cap, _Cap rev_cap = 0) 223 | { 224 | 225 | std::size_t old_size = m_edges.size(); 226 | node* node_i = m_nodes.ptr_at(i); 227 | node* node_j = m_nodes.ptr_at(j); 228 | 229 | edge* fwd_edge = m_edges.grow(); 230 | edge* rev_edge = m_edges.grow(); 231 | fwd_edge->m_head = node_j; 232 | fwd_edge->m_rcap = fwd_cap; 233 | fwd_edge->m_sister = rev_edge; 234 | rev_edge->m_head = node_i; 235 | rev_edge->m_rcap = rev_cap; 236 | rev_edge->m_sister = fwd_edge; 237 | 238 | node_i->m_out_edges->push_back(fwd_edge); 239 | node_j->m_out_edges->push_back(rev_edge); 240 | 241 | return old_size; 242 | } 243 | 244 | /// \brief Get total number of non-terminal edges in the graph. 245 | inline std::size_t get_edge_cnt(){ return m_edges.size(); } 246 | 247 | /// \brief Get the number of non-terminal edges start from node i. 248 | inline std::size_t get_outgoing_edge_cnt(std::size_t i){ assert(isize(); } 249 | 250 | /// \brief Solve the maximum-flow/minimum s-t cut problem and returns the maximum flow value. 251 | /// 252 | /// \note Not used for search tree reuse. 253 | _Cap solve(); 254 | 255 | /// \brief Determines if the given node is in the source set of the cut. 256 | /// 257 | /// \param i index of the node 258 | /// \return true if the given node is the source set, false otherwise. 259 | inline bool in_source_set(std::size_t i) 260 | { 261 | assert(iis_sink() == false) && p_node->has_parent(); 264 | } 265 | 266 | }; // end of class graph 267 | 268 | } // end of namespace 269 | 270 | #include "logismos_graph.cxx" 271 | 272 | #endif 273 | --------------------------------------------------------------------------------