├── test ├── Input │ ├── DSA.png.md5 │ ├── cthead1.png.md5 │ └── VM1111Shrink-LAB.mha ├── Baseline │ ├── ObjectnessMeasureImageFilterTest1.nii.md5 │ ├── ObjectnessMeasureImageFilterTest2.nii.md5 │ ├── itkSLICImageFilterTest1Baseline.nii.md5 │ └── itkSLICImageFilterTest3Baseline.nii.md5 ├── ci │ ├── CacheAndUpdateITK.sh │ ├── travis_dashboard.cmake │ ├── appveyor_dashboard.cmake │ └── common_dashboard.cmake ├── itkFunctorsTest.cxx ├── itkSLICImageFilterTest2.cxx ├── itkHessianImageFilterTest.cxx ├── itkObjectnessMeasureImageFilterTest.cxx ├── CMakeLists.txt ├── itkSLICImageFilterTest.cxx └── itkSliceImageFilterTest.cxx ├── CMakeLists.txt ├── .gitignore ├── appveyor.yml ├── .travis.yml ├── itk-module.cmake ├── include ├── itkUnaryMinusFunctor.h ├── itkBitwiseNotFunctor.h ├── itkDivideFloorFunctor.h ├── itkDivideRealFunctor.h ├── itkHessianImageFilter.h ├── itkObjectnessMeasureImageFilter.hxx ├── itkObjectnessMeasureImageFilter.h ├── itkHessianImageFilter.hxx ├── itkSliceImageFilter.h ├── itkSLICImageFilter.h ├── itkSliceImageFilter.hxx └── itkSLICImageFilter.hxx ├── README.rst ├── CMake ├── UseGTest.cmake └── External_GTest.cmake └── LICENSE /test/Input/DSA.png.md5: -------------------------------------------------------------------------------- 1 | 02e576585b1d28ad4d016129be2aa224 2 | -------------------------------------------------------------------------------- /test/Input/cthead1.png.md5: -------------------------------------------------------------------------------- 1 | b23198c9e44a48edfd5b83f075eb455c 2 | -------------------------------------------------------------------------------- /test/Baseline/ObjectnessMeasureImageFilterTest1.nii.md5: -------------------------------------------------------------------------------- 1 | 1fdb74a9029cf33147ace42e2d6c8f15 2 | -------------------------------------------------------------------------------- /test/Baseline/ObjectnessMeasureImageFilterTest2.nii.md5: -------------------------------------------------------------------------------- 1 | 68046dd24c7824ef346d5a219e271d47 2 | -------------------------------------------------------------------------------- /test/Baseline/itkSLICImageFilterTest1Baseline.nii.md5: -------------------------------------------------------------------------------- 1 | b89d2aa43e79fb34a639431027473332 2 | -------------------------------------------------------------------------------- /test/Baseline/itkSLICImageFilterTest3Baseline.nii.md5: -------------------------------------------------------------------------------- 1 | 686e6715e45eef7e4d8b4f8ec701e571 2 | -------------------------------------------------------------------------------- /test/Input/VM1111Shrink-LAB.mha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimpleITK/itkSimpleITKFiltersModule/master/test/Input/VM1111Shrink-LAB.mha -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.9) 2 | 3 | if(POLICY CMP0063) 4 | cmake_policy(SET CMP0063 NEW) 5 | endif() 6 | 7 | project(SimpleITKFiltersModule) 8 | 9 | if(NOT ITK_SOURCE_DIR) 10 | find_package(ITK REQUIRED) 11 | list(APPEND CMAKE_MODULE_PATH ${ITK_CMAKE_DIR}) 12 | include(ITKModuleExternal) 13 | else() 14 | itk_module_impl() 15 | endif() 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Do not add ExternalData module staging files 2 | .ExternalData* 3 | 4 | # back-up files 5 | *~ 6 | *.bak 7 | 8 | # KWStyle hook output 9 | *.kws 10 | 11 | # compiled python files 12 | *.pyc 13 | 14 | # Binary directory 15 | BUILD* 16 | build* 17 | 18 | # qtcreator 19 | CMakeLists.txt.user* 20 | 21 | # kdevelop 22 | *.kdev* 23 | .kdev* 24 | 25 | # back-up files when conflicts occur 26 | *.orig 27 | -------------------------------------------------------------------------------- /test/ci/CacheAndUpdateITK.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | mkdir -p "${ExternalData_OBJECT_STORES}" 4 | 5 | echo "Using ITK repository: ${ITK_REPOSITORY_REMOTE:=https://github.com/InsightSoftwareConsortium/ITK.git}" 6 | 7 | if [ -n "${APPVEYOR_BUILD_FOLDER+x}" ] 8 | then 9 | PROJ_SRC=${APPVEYOR_BUILD_FOLDER} 10 | fi 11 | 12 | 13 | git clone --single-branch ${ITK_REPOSITORY_REMOTE} -b "${ITK_TAG}" "${ITK_SRC}" && 14 | ( cd ${ITK_SRC}/Modules/Remote && 15 | ln -s ${PROJ_SRC} ${ITK_MODULE_NAME} 16 | ) 17 | 18 | ( cd ${PROJ_SRC}/test && 19 | git clone --single-branch ${ITK_REPOSITORY_REMOTE} -b dashboard dashboard 20 | ) 21 | -------------------------------------------------------------------------------- /test/ci/travis_dashboard.cmake: -------------------------------------------------------------------------------- 1 | # Client maintainer: blowekamp@mail.nih.gov 2 | execute_process(COMMAND hostname OUTPUT_VARIABLE hostname OUTPUT_STRIP_TRAILING_WHITESPACE) 3 | set(CTEST_SITE "${hostname}") 4 | set(CTEST_DASHBOARD_ROOT $ENV{TRAVIS_BUILD_DIR}/..) 5 | get_filename_component(compiler_name $ENV{CC} NAME) 6 | string(SUBSTRING $ENV{TRAVIS_COMMIT} 0 7 commit) 7 | 8 | set(what "#$ENV{TRAVIS_PULL_REQUEST}") 9 | if($ENV{TRAVIS_PULL_REQUEST} STREQUAL "false") 10 | set(what "$ENV{TRAVIS_BRANCH}") 11 | endif() 12 | set(CTEST_BUILD_NAME "$ENV{ITK_MODULE_NAME}-$ENV{TRAVIS_OS_NAME}-${compiler_name}_${what}_${commit}") 13 | 14 | set(CTEST_CONFIGURATION_TYPE Release) 15 | set(CTEST_CMAKE_GENERATOR "Unix Makefiles") 16 | 17 | list(APPEND CTEST_NOTES_FILES 18 | "$ENV{PROJ_SRC}/.travis.yml" 19 | ) 20 | 21 | include("${CTEST_SCRIPT_DIRECTORY}/common_dashboard.cmake") 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | branches: 2 | only: 3 | - master 4 | - /^ci.*$/ 5 | 6 | platform: 7 | - x86 8 | 9 | configuration: 10 | - Release 11 | 12 | cache: 13 | - '%USERPROFILE%\ExternalData' 14 | 15 | environment: 16 | global: 17 | CYG_ROOT: C:\cygwin 18 | ExternalData_OBJECT_STORES: '%USERPROFILE%\ExternalData' 19 | PROJ_SRC: '%APPVEYOR_BUILD_FOLDER%' 20 | ITK_MODULE_NAME: SimpleITKFiltersModule 21 | ITK_TAG: master 22 | ITK_SRC: 'C:\ITK' 23 | 24 | matrix: 25 | - GENERATOR: "Visual Studio 9 2008" 26 | - GENERATOR: "Visual Studio 11 2012 Win64" 27 | - GENERATOR: "Visual Studio 14 2015 Win64" 28 | 29 | install: 30 | - '%CYG_ROOT%/bin/bash -x "%PROJ_SRC%\test\ci\CacheAndUpdateITK.sh"' 31 | 32 | build_script: 33 | - ctest -V -C %configuration% -S "%APPVEYOR_BUILD_FOLDER%\\test\\ci\\appveyor_dashboard.cmake" 34 | 35 | test: off 36 | 37 | deploy: off 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: cpp 3 | 4 | env: 5 | global: 6 | - ExternalData_OBJECT_STORES="${HOME}/.ExternalData" 7 | - PROJ_SRC="${TRAVIS_BUILD_DIR}" 8 | - ITK_MODULE_NAME=SimpleITKFiltersModule 9 | - ITK_TAG=master 10 | - ITK_SRC="${HOME}/ITK" 11 | 12 | cache: 13 | directories: 14 | - ${ExternalData_OBJECT_STORES} 15 | 16 | matrix: 17 | include: 18 | - os: linux 19 | dist: trusty 20 | sudo: required 21 | - os: osx 22 | osx_image: xcode7.3 23 | 24 | 25 | before_install: 26 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi 27 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ninja $( command -V cmake &>2 /dev/null || echo "cmake" ); fi 28 | 29 | before_script: 30 | - cmake --version 31 | - env 32 | - bash -x ${PROJ_SRC}/test/ci/CacheAndUpdateITK.sh 33 | 34 | script: 35 | - ctest -V -S ${PROJ_SRC}/test/ci/travis_dashboard.cmake 36 | -------------------------------------------------------------------------------- /itk-module.cmake: -------------------------------------------------------------------------------- 1 | get_filename_component( MY_CURENT_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 2 | file( READ "${MY_CURENT_DIR}/README.rst" DOCUMENTATION ) 3 | 4 | 5 | # ITK version 4.5 changed it from EXCLUDE_FROM_ALL to EXCLUDE_FROM_DEFAULT 6 | set( _EXCLUDE "EXCLUDE_FROM_ALL" ) 7 | if (NOT "${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}.${ITK_VERSION_MINOR_PATCH}" VERSION_LESS "4.5") 8 | set( _EXCLUDE "EXCLUDE_FROM_DEFAULT" ) 9 | endif() 10 | 11 | # itk_module() defines the module dependencies in SimpleITKFiltersModule 12 | # SimpleITKFiltersModule depends on ITKCommon 13 | # The testing module in SimpleITKFiltersModule depends on ITKTestKernel 14 | # and ITKMetaIO(besides SimpleITKFiltersModule and ITKCore) 15 | # By convention those modules outside of ITK are not prefixed with 16 | # ITK. 17 | 18 | # define the dependencies of the include module and the tests 19 | itk_module(SimpleITKFiltersModule 20 | DEPENDS 21 | ITKImageFeature 22 | TEST_DEPENDS 23 | ITKTestKernel 24 | ITKImageSources 25 | DESCRIPTION 26 | "${DOCUMENTATION}" 27 | ${_EXCLUDE} 28 | ) 29 | -------------------------------------------------------------------------------- /test/ci/appveyor_dashboard.cmake: -------------------------------------------------------------------------------- 1 | # Client maintainer: blowekamp@mail.nih.gov 2 | set(CTEST_SITE "appveyor") 3 | set(CTEST_DASHBOARD_ROOT $ENV{APPVEYOR_BUILD_FOLDER}/..) 4 | string(SUBSTRING $ENV{APPVEYOR_REPO_COMMIT} 0 7 commit) 5 | 6 | # Extract major/minor/patch versions 7 | 8 | set(what "$ENV{APPVEYOR_PULL_REQUEST_TITLE}_#$ENV{APPVEYOR_PULL_REQUEST_NUMBER}") 9 | if("$ENV{APPVEYOR_PULL_REQUEST_NUMBER}" STREQUAL "") 10 | set(what "$ENV{APPVEYOR_REPO_BRANCH}") 11 | endif() 12 | set(CTEST_CONFIGURATION_TYPE $ENV{CONFIGURATION}) 13 | set(CTEST_CMAKE_GENERATOR "$ENV{GENERATOR}") 14 | if("${CTEST_CMAKE_GENERATOR}" STREQUAL "") 15 | set(CTEST_CMAKE_GENERATOR "Visual Studio 9 2008") 16 | endif() 17 | 18 | set(platform $ENV{PLATFORM}) 19 | 20 | set(CTEST_BUILD_NAME "$ENV{ITK_MODULE_NAME}-VS-${platform}-$ENV{CONFIGURATION}_${what}_${commit}") 21 | 22 | list(APPEND CTEST_NOTES_FILES 23 | # The PROJ_SRC env contains another %env% which is not being evaluated 24 | # "$ENV{PROJ_SRC}/appveyor.yml" 25 | ) 26 | 27 | include("${CTEST_SCRIPT_DIRECTORY}/common_dashboard.cmake") 28 | -------------------------------------------------------------------------------- /include/itkUnaryMinusFunctor.h: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkUnaryMinusFunctor_h 19 | #define itkUnaryMinusFunctor_h 20 | 21 | namespace itk 22 | { 23 | namespace Functor 24 | { 25 | /** 26 | * \class UnaryMinus 27 | * \brief Applies the unary minus operator to the argument. 28 | * 29 | * \ingroup SimpleITKFiltersModule 30 | */ 31 | template< class TInput1, class TOutput = TInput1 > 32 | class UnaryMinus 33 | { 34 | public: 35 | UnaryMinus() {} 36 | ~UnaryMinus() {} 37 | bool operator!=(const UnaryMinus &) const 38 | { 39 | return false; 40 | } 41 | 42 | bool operator==(const UnaryMinus & other) const 43 | { 44 | return !( *this != other ); 45 | } 46 | 47 | inline TOutput operator()(const TInput1 & A ) const 48 | { return (TOutput)( -A ); } 49 | }; 50 | } 51 | } 52 | 53 | #endif // itkUnaryMinusFunctor_h 54 | -------------------------------------------------------------------------------- /include/itkBitwiseNotFunctor.h: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkBitwiseNotFunctor_h 19 | #define itkBitwiseNotFunctor_h 20 | 21 | #include 22 | 23 | namespace itk 24 | { 25 | namespace Functor 26 | { 27 | /** 28 | * \class BitwiseNot 29 | * \brief Performs the C++ unary bitwise NOT operator. 30 | * 31 | * \ingroup SimpleITKFiltersModule 32 | */ 33 | template< class TInput, class TOutput > 34 | class BitwiseNot 35 | { 36 | public: 37 | // Use default copy, assigned and destructor 38 | // BitwiseNot() {} default constructor OK 39 | 40 | bool operator!=(const BitwiseNot &) const 41 | { 42 | return false; 43 | } 44 | 45 | bool operator==(const BitwiseNot & other) const 46 | { 47 | return !( *this != other ); 48 | } 49 | 50 | inline TOutput operator()(const TInput & A) const 51 | { 52 | return static_cast( ~A ); 53 | } 54 | }; 55 | } 56 | } 57 | 58 | #endif // itkBitwiseNotFunctor_h 59 | -------------------------------------------------------------------------------- /test/ci/common_dashboard.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Example Dashboard script for CI services 3 | # 4 | # Used environment variable: 5 | # ITK_MODULE_NAME - name of the ITK external/remote module 6 | # ITK_SRC - ITK source directory ( already upto date ) 7 | # ITK_REPOSITORY - local or remote repository 8 | # ITK_TAG - name of ITK tag or branch 9 | set(itk_module "$ENV{ITK_MODULE_NAME}") 10 | 11 | set(dashboard_no_update 0) 12 | if(DEFINED ENV{ITK_SRC}) 13 | set(CTEST_SOURCE_DIRECTORY "$ENV{ITK_SRC}") 14 | set(dashboard_no_update 1) 15 | elseif(DEFINED ENV{ITK_REPOSITORY}) 16 | set(dashboard_git_url "$ENV{ITK_REPOSITORY}") 17 | set(dashboard_git_branch "$ENV{ITK_TAG}") 18 | set(CTEST_DASHBOARD_ROOT "$ENV{HOME}/dash") 19 | endif() 20 | 21 | set(CTEST_BUILD_TARGET "${itk_module}-all") 22 | set(CTEST_TEST_ARGS INCLUDE_LABEL ${itk_module}) 23 | 24 | set(dashboard_model "Experimental") 25 | set(dashboard_track "Remote") 26 | 27 | include( ProcessorCount ) 28 | ProcessorCount( PROCESSOR_COUNT ) 29 | if(PROCESSOR_COUNT) 30 | if (CTEST_CMAKE_GENERATOR STREQUAL "Unix Makefiles") 31 | set( CTEST_BUILD_FLAGS -j${PROCESSOR_COUNT}) 32 | endif() 33 | set( CTEST_TEST_ARGS ${CTEST_TEST_ARGS} PARALLEL_LEVEL ${PROCESSOR_COUNT} ) 34 | endif() 35 | 36 | 37 | # this is the initial cache to use for the binary tree. 38 | SET (dashboard_cache " 39 | 40 | BUILD_DOCUMENTATION:BOOL=OFF 41 | BUILD_EXAMPLES:BOOL=OFF 42 | BUILD_SHARED_LIBS:BOOL=OFF 43 | BUILD_TESTING:BOOL=ON 44 | ITK_USE_KWSTYLE:BOOL=OFF 45 | 46 | ITK_BUILD_DEFAULT_MODULES:BOOL=OFF 47 | Module_${itk_module}:BOOL=ON 48 | " ) 49 | 50 | list(APPEND CTEST_NOTES_FILES 51 | "${CMAKE_CURRENT_LIST_FILE}" 52 | ) 53 | 54 | include(${CTEST_SCRIPT_DIRECTORY}/../dashboard/itk_common.cmake) 55 | 56 | -------------------------------------------------------------------------------- /include/itkDivideFloorFunctor.h: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkDivideFloorFunctor_h 19 | #define itkDivideFloorFunctor_h 20 | 21 | #include 22 | #include 23 | 24 | namespace itk 25 | { 26 | namespace Functor 27 | { 28 | /** 29 | * \class DivFloor 30 | * \brief Cast arguments to double, performs division then takes the floor. 31 | * 32 | * If the second operand is 0 then NumericTraits::max is 33 | * returned. 34 | * 35 | * \ingroup SimpleITKFiltersModule 36 | */ 37 | template< class TInput1, class TInput2, class TOutput > 38 | class DivFloor 39 | { 40 | public: 41 | // Use default copy, assigned and destructor 42 | // DivFloor() {} default constructor OK 43 | 44 | bool operator!=(const DivFloor &) const 45 | { 46 | return false; 47 | } 48 | 49 | bool operator==(const DivFloor & other) const 50 | { 51 | return !( *this != other ); 52 | } 53 | 54 | inline TOutput operator()(const TInput1 & A, const TInput2 & B) const 55 | { 56 | if ( B != (TInput2)0 ) 57 | { 58 | return static_cast( std::floor( double(A) / double(B) ) ); 59 | } 60 | else 61 | { 62 | return NumericTraits< TOutput >::max( static_cast(A) ); 63 | } 64 | } 65 | }; 66 | } 67 | } 68 | 69 | #endif // itkDivisionFloorImageFilter_h 70 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | General 2 | ======= 3 | 4 | .. image:: https://ci.appveyor.com/api/projects/status/je74aykgrftxxkdd/branch/master?svg=true 5 | :target: https://ci.appveyor.com/project/blowekamp/itksimpleitkfiltersmodule-muow0/branch/master 6 | 7 | .. image:: https://travis-ci.org/SimpleITK/itkSimpleITKFiltersModule.svg?branch=master 8 | :target: https://travis-ci.org/SimpleITK/itkSimpleITKFiltersModule 9 | 10 | This is a module for `ITK `_: The Insight Toolkit for Segmentation and 11 | Registration. It is designed to work with the ITKv4 12 | modular system and to be places it ITK/Modules/External or uses as a 13 | Remote module. 14 | 15 | This SimpleITKFilters module is a collection of ITK Filters used by SimpleITK. 16 | 17 | Getting Started 18 | =============== 19 | 20 | The official ITKv4 Wiki documentation on adding an external module is here: 21 | 22 | * http://www.itk.org/Wiki/ITK_Release_4/Modularization/Add_an_external_module_(external_module) 23 | * http://www.itk.org/Wiki/ITK/Policy_and_Procedures_for_Adding_Remote_Modules 24 | 25 | 26 | External Module 27 | --------------- 28 | 29 | The following is a breif list of instructions to get a external module 30 | started in a repository:: 31 | 32 | mkdir ITK/Modules/External/itkMyModule 33 | cd ITK/Modules/External/itkMyModule 34 | git init 35 | git fetch git@github.com:blowekamp/itkExternalTemplate.git 36 | git merge FETCH_HEAD 37 | 38 | Remote Module 39 | ------------- 40 | 41 | After a module has been created as a git repository it can be included 42 | as a remote module, which enables automatic fetching. Add a file in 43 | "ITK/Modules/Remote" called "YourModule.remote.cmake", for this module 44 | it would be "ExternalExample.remote.cmake" with the followlowing contents:: 45 | 46 | itk_fetch_module(ExternalTemplate 47 | "A template for a module." 48 | GIT_REPOSITORY http://github.com/blowekamp/itkExternalTemplate.git 49 | GIT_TAG master 50 | ) 51 | 52 | License 53 | ======= 54 | 55 | This software is distributed under the Apache License. Please see 56 | LICENSE for details. 57 | 58 | 59 | Authors 60 | ======= 61 | 62 | * Bradley Lowekamp 63 | -------------------------------------------------------------------------------- /include/itkDivideRealFunctor.h: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkDivideRealFunctor_h 19 | #define itkDivideRealFunctor_h 20 | 21 | #include 22 | 23 | namespace itk 24 | { 25 | namespace Functor 26 | { 27 | /** 28 | * \class DivReal 29 | * \brief Promotes arguments to real type and performs division 30 | * 31 | * The result is then static_cast'ed to the output pixel type. 32 | * 33 | * \ingroup SimpleITKFiltersModule 34 | */ 35 | template< class TInput1, class TInput2, class TOutput > 36 | class DivReal 37 | { 38 | public: 39 | // Use default copy, assigned and destructor 40 | bool operator!=(const DivReal &) const 41 | { 42 | return false; 43 | } 44 | 45 | bool operator==(const DivReal & other) const 46 | { 47 | return !( *this != other ); 48 | } 49 | 50 | inline TOutput operator()(const TInput1 & A, const TInput2 & B) const 51 | { 52 | if ( B != (TInput2)0 ) 53 | { 54 | return static_cast( static_cast::RealType>(A) 55 | / 56 | static_cast::RealType >(B) ); 57 | } 58 | else 59 | { 60 | return NumericTraits< TOutput >::max( static_cast(A) ); 61 | } 62 | } 63 | }; 64 | } 65 | } 66 | 67 | #endif // itkDivisionRealImageFilter_h 68 | -------------------------------------------------------------------------------- /test/itkFunctorsTest.cxx: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #include "itkSliceImageFilter.h" 20 | 21 | #include "itkBitwiseNotFunctor.h" 22 | #include "itkDivideFloorFunctor.h" 23 | #include "itkDivideRealFunctor.h" 24 | #include "itkUnaryMinusFunctor.h" 25 | 26 | #include "gtest/gtest.h" 27 | 28 | 29 | TEST(BitwiseNotFunctorTest, Test1) 30 | { 31 | 32 | 33 | itk::Functor::BitwiseNot f; 34 | itk::Functor::BitwiseNot f2; 35 | 36 | 37 | EXPECT_FALSE(f != f2); 38 | EXPECT_TRUE(f == f2); 39 | EXPECT_TRUE(f == f); 40 | 41 | EXPECT_EQ(254, f(1)); 42 | EXPECT_EQ(1, f(f(1))); 43 | 44 | 45 | itk::Functor::BitwiseNot f3; 46 | 47 | EXPECT_EQ(0,f3(-1)); 48 | EXPECT_EQ(-1,f3(f3(-1))); 49 | } 50 | 51 | 52 | TEST(DivideFloorFunctorTest, Test1) 53 | { 54 | itk::Functor::DivFloor f; 55 | 56 | EXPECT_TRUE(f==f); 57 | EXPECT_FALSE(f!=f); 58 | 59 | EXPECT_EQ(2, f(5,2)); 60 | EXPECT_EQ(-2, f(8,-7)); 61 | } 62 | 63 | 64 | TEST(DivideRealFunctorTest, Test1) 65 | { 66 | 67 | itk::Functor::DivReal f; 68 | 69 | EXPECT_TRUE(f==f); 70 | EXPECT_FALSE(f!=f); 71 | 72 | EXPECT_FLOAT_EQ(2.5, f(5,2)); 73 | } 74 | 75 | TEST(UnaryMinusFunctorTest, Test1) 76 | { 77 | itk::Functor::UnaryMinus f; 78 | 79 | EXPECT_TRUE(f==f); 80 | EXPECT_FALSE(f!=f); 81 | 82 | EXPECT_EQ(-1.0f, f(1.0f)); 83 | EXPECT_EQ(1.0f, f(-1.0f)); 84 | EXPECT_EQ(0.0f, f(0.0f)); 85 | } 86 | -------------------------------------------------------------------------------- /test/itkSLICImageFilterTest2.cxx: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #include "itkSLICImageFilter.h" 20 | #include "itkVectorImage.h" 21 | #include "itkRandomImageSource.h" 22 | 23 | 24 | namespace 25 | { 26 | } 27 | 28 | int itkSLICImageFilterTest2(int, char *[]) 29 | { 30 | const unsigned int gridSize = 50; 31 | const float proximityWeight = 10.0; 32 | 33 | const unsigned int VDimension = 2; 34 | typedef itk::VectorImage InputImageType; 35 | typedef itk::Image OutputImageType; 36 | 37 | InputImageType::Pointer input = InputImageType::New(); 38 | 39 | InputImageType::RegionType region; 40 | InputImageType::SizeType size = {{gridSize+1, gridSize+1}}; 41 | region.SetSize( size ); 42 | input->SetRegions(region); 43 | input->SetVectorLength(3); 44 | input->Allocate(); 45 | 46 | typedef itk::SLICImageFilter< InputImageType, OutputImageType > FilterType; 47 | FilterType::Pointer filter = FilterType::New(); 48 | filter->SetSpatialProximityWeight(proximityWeight); 49 | filter->SetInput(input); 50 | 51 | 52 | // check case where grid size is bigger than image 53 | filter->SetSuperGridSize(gridSize); 54 | filter->Update(); 55 | 56 | // check case where more threads than slices 57 | input->Modified(); 58 | filter->SetNumberOfThreads(125); 59 | filter->Update(); 60 | 61 | // check 1x1 image 62 | InputImageType::SizeType size2 = {{1,1}}; 63 | region.SetSize( size2 ); 64 | input->SetRegions(region); 65 | input->Allocate(); 66 | filter->Update(); 67 | 68 | filter->GetOutput()->Print(std::cout); 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /test/itkHessianImageFilterTest.cxx: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #include "itkHessianImageFilter.h" 19 | #include "itkGaussianImageSource.h" 20 | #include "itkImageFileReader.h" 21 | 22 | int itkHessianImageFilterTest( int , char *[] ) 23 | { 24 | const unsigned int Dimension = 3; 25 | typedef itk::Image< float, Dimension > ImageType; 26 | 27 | const unsigned int imageSize = 64; 28 | 29 | ImageType::SizeType size; 30 | size.Fill( imageSize ); 31 | 32 | ImageType::SpacingType spacing; 33 | spacing.Fill( 1.0 ); 34 | spacing[0] = 1.0; 35 | 36 | typedef itk::GaussianImageSource GaussianSourceType; 37 | GaussianSourceType::Pointer gaussianSource = GaussianSourceType::New(); 38 | gaussianSource->SetSize( size ); 39 | gaussianSource->SetSpacing( spacing ); 40 | gaussianSource->SetMean( itk::FixedArray< double, Dimension>( imageSize/2 ) ); 41 | gaussianSource->SetSigma( itk::FixedArray< double, Dimension>( 10.0 ) ); 42 | gaussianSource->SetNormalized( false ); 43 | gaussianSource->SetScale( 1.0 ); // dark blob 44 | 45 | typedef itk::HessianImageFilter< ImageType > HessianFilterType; 46 | HessianFilterType::Pointer hessian = HessianFilterType::New(); 47 | hessian->SetInput( gaussianSource->GetOutput() ); 48 | hessian->Update(); 49 | 50 | HessianFilterType:: OutputPixelType H; 51 | 52 | ImageType::IndexType idx; 53 | idx.Fill( imageSize/2 ); 54 | H = hessian->GetOutput()->GetPixel( idx ); 55 | 56 | 57 | --idx[0]; 58 | std::cout << hessian->GetOutput()->GetPixel( idx ) << std::endl; 59 | 60 | --idx[1]; 61 | std::cout << hessian->GetOutput()->GetPixel( idx ) << std::endl; 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /test/itkObjectnessMeasureImageFilterTest.cxx: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #include "itkTestingMacros.h" 20 | #include "itkFilterWatcher.h" 21 | #include "itkObjectnessMeasureImageFilter.h" 22 | #include "itkSmoothingRecursiveGaussianImageFilter.h" 23 | #include "itkImageFileReader.h" 24 | #include "itkImageFileWriter.h" 25 | 26 | int itkObjectnessMeasureImageFilterTest(int argc, char *argv[]) 27 | { 28 | if( argc < 3 ) 29 | { 30 | std::cerr << "Usage: " << argv[0] << " inputImage outputImage [ObjectDimension] [Bright/Dark]" << std::endl; 31 | return EXIT_FAILURE; 32 | } 33 | const char *inputImageFileName = argv[1]; 34 | const char *outputImageFileName = argv[2]; 35 | 36 | const unsigned int objectDimension = (argc >= 3) ? atoi(argv[3]) : 3; 37 | const bool brightObject = (argc >= 4) ? atoi(argv[4]) : true; 38 | const double alphaValue = 0.5; 39 | const double betaValue = 0.5; 40 | const double gammaValue = 0.5; 41 | 42 | const unsigned int Dimension = 2; 43 | typedef double PixelType; 44 | typedef itk::Image< PixelType, Dimension > ImageType; 45 | 46 | typedef itk::ImageFileReader ReaderType; 47 | ReaderType::Pointer reader = ReaderType::New(); 48 | reader->SetFileName( inputImageFileName ); 49 | 50 | typedef itk::SmoothingRecursiveGaussianImageFilter SmoothingFilterType; 51 | SmoothingFilterType::Pointer smoothing = SmoothingFilterType::New(); 52 | smoothing->SetSigma(1.0); 53 | smoothing->SetInput(reader->GetOutput()); 54 | 55 | typedef itk::ObjectnessMeasureImageFilter FilterType; 56 | FilterType::Pointer filter = FilterType::New(); 57 | filter->SetInput(smoothing->GetOutput()); 58 | filter->SetAlpha(alphaValue); 59 | filter->SetBeta(betaValue); 60 | filter->SetGamma(gammaValue); 61 | filter->SetBrightObject(brightObject); 62 | filter->SetObjectDimension(objectDimension); 63 | filter->SetScaleObjectnessMeasure(false); 64 | 65 | FilterWatcher watcher(filter); 66 | 67 | typedef itk::ImageFileWriter WriterType; 68 | WriterType::Pointer writer = WriterType::New(); 69 | writer->SetInput(filter->GetOutput()); 70 | writer->SetFileName( outputImageFileName ); 71 | writer->Update(); 72 | 73 | //EXERCISE_BASIC_OBJECT_METHODS( FilterType, ObjectnessMeasureImageFilter ); 74 | 75 | return EXIT_SUCCESS; 76 | } 77 | -------------------------------------------------------------------------------- /CMake/UseGTest.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # UseGTest 3 | # --------- 4 | # 5 | # Deeper integration with CTest 6 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7 | # 8 | # If you would like each Google test to show up in CTest as a test you 9 | # may use the following macro:: 10 | # 11 | # GTEST_ADD_TESTS(executable extra_args files...) 12 | # 13 | # ``executable`` 14 | # the path to the test executable 15 | # ``extra_args`` 16 | # a list of extra arguments to be passed to executable enclosed in 17 | # quotes (or ``""`` for none) 18 | # ``files...`` 19 | # a list of source files to search for tests and test fixtures. Or 20 | # ``AUTO`` to find them from executable target 21 | # 22 | # However, note that this macro will slow down your tests by running 23 | # an executable for each test and test fixture. You will also have to 24 | # re-run CMake after adding or removing tests or test fixtures. 25 | # 26 | # Example usage:: 27 | # 28 | # set(FooTestArgs --foo 1 --bar 2) 29 | # add_executable(FooTest FooUnitTest.cc) 30 | # GTEST_ADD_TESTS(FooTest "${FooTestArgs}" AUTO) 31 | 32 | #============================================================================= 33 | # Copyright 2009 Kitware, Inc. 34 | # Copyright 2009 Philip Lowman 35 | # Copyright 2009 Daniel Blezek 36 | # 37 | # Distributed under the OSI-approved BSD License (the "License"); 38 | # see accompanying file Copyright.txt for details. 39 | # 40 | # This software is distributed WITHOUT ANY WARRANTY; without even the 41 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 42 | # See the License for more information. 43 | #============================================================================= 44 | # (To distribute this file outside of CMake, substitute the full 45 | # License text for the above reference.) 46 | # 47 | # Thanks to Daniel Blezek for the GTEST_ADD_TESTS code 48 | # 49 | # ADDITIONS 50 | # Set test label to itk_module if defined. 51 | # 52 | function(GTEST_ADD_TESTS executable extra_args) 53 | if(NOT ARGN) 54 | message(FATAL_ERROR "Missing ARGN: Read the documentation for GTEST_ADD_TESTS") 55 | endif() 56 | if(ARGN STREQUAL "AUTO") 57 | # obtain sources used for building that executable 58 | get_property(ARGN TARGET ${executable} PROPERTY SOURCES) 59 | endif() 60 | set(gtest_case_name_regex ".*\\( *([A-Za-z_0-9]+) *, *([A-Za-z_0-9]+) *\\).*") 61 | set(gtest_test_type_regex "(TYPED_TEST|TEST_?[FP]?)") 62 | foreach(source ${ARGN}) 63 | file(READ "${source}" contents) 64 | string(REGEX MATCHALL "${gtest_test_type_regex} *\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents}) 65 | foreach(hit ${found_tests}) 66 | string(REGEX MATCH "${gtest_test_type_regex}" test_type ${hit}) 67 | 68 | # Parameterized tests have a different signature for the filter 69 | if("x${test_type}" STREQUAL "xTEST_P") 70 | string(REGEX REPLACE ${gtest_case_name_regex} "*/\\1.\\2/*" test_name ${hit}) 71 | elseif("x${test_type}" STREQUAL "xTEST_F" OR "x${test_type}" STREQUAL "xTEST") 72 | string(REGEX REPLACE ${gtest_case_name_regex} "\\1.\\2" test_name ${hit}) 73 | elseif("x${test_type}" STREQUAL "xTYPED_TEST") 74 | string(REGEX REPLACE ${gtest_case_name_regex} "\\1/*.\\2" test_name ${hit}) 75 | else() 76 | message(WARNING "Could not parse GTest ${hit} for adding to CTest.") 77 | continue() 78 | endif() 79 | add_test(NAME ${test_name} COMMAND ${executable} --gtest_filter=${test_name} ${extra_args}) 80 | 81 | # 82 | # Addition from upstream CMake version. 83 | # 84 | if(itk-module) 85 | set_property(TEST ${test_name} PROPERTY LABELS ${itk-module}) 86 | endif() 87 | # 88 | # 89 | # 90 | endforeach() 91 | endforeach() 92 | endfunction() 93 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | itk_module_test() 2 | 3 | #${itk-module} will be the name of this module and will not need to be 4 | #changed when this module is renamed. 5 | 6 | set(${itk-module}Tests 7 | itkObjectnessMeasureImageFilterTest.cxx 8 | itkHessianImageFilterTest.cxx 9 | itkSLICImageFilterTest.cxx 10 | itkSLICImageFilterTest2.cxx 11 | ) 12 | 13 | 14 | set(BASELINE_ROOT ${ITK_DATA_ROOT}/Baseline) 15 | set(TEMP ${ITK_TEST_OUTPUT_DIR}) 16 | 17 | CreateTestDriver(${itk-module} "${${itk-module}-Test_LIBRARIES}" "${${itk-module}Tests}") 18 | 19 | itk_add_test(NAME itkObjectnessMeasureImageFilterTest1 20 | COMMAND ${itk-module}TestDriver 21 | --compareIntensityTolerance .001 22 | --compare 23 | DATA{Baseline/ObjectnessMeasureImageFilterTest1.nii} 24 | ${TEMP}/ObjectnessMeasureImageFilterTestOutput1.nii 25 | itkObjectnessMeasureImageFilterTest 26 | DATA{Input/DSA.png} 27 | ${TEMP}/ObjectnessMeasureImageFilterTestOutput1.nii 28 | 1 0 29 | ) 30 | 31 | itk_add_test(NAME itkObjectnessMeasureImageFilterTest2 32 | COMMAND ${itk-module}TestDriver 33 | --compareIntensityTolerance .001 34 | --compare 35 | DATA{Baseline/ObjectnessMeasureImageFilterTest2.nii} 36 | ${TEMP}/ObjectnessMeasureImageFilterTestOutput2.nii 37 | itkObjectnessMeasureImageFilterTest 38 | DATA{Input/DSA.png} 39 | ${TEMP}/ObjectnessMeasureImageFilterTestOutput2.nii 40 | 0 0 41 | ) 42 | 43 | add_test(NAME itkHessianImageFilterTest 44 | COMMAND ${itk-module}TestDriver itkHessianImageFilterTest ) 45 | 46 | itk_add_test(NAME itkSLICImageFilterTest_1 47 | COMMAND ${itk-module}TestDriver 48 | --with-threads 1 49 | --compare DATA{Baseline/itkSLICImageFilterTest1Baseline.nii} 50 | ${TEMP}/itkSLICImageFilterTest1Output.nii 51 | itkSLICImageFilterTest 52 | DATA{Input/VM1111Shrink-LAB.mha} 53 | ${TEMP}/itkSLICImageFilterTest1Output.nii 25 ) 54 | 55 | itk_add_test(NAME itkSLICImageFilterTest_2 56 | COMMAND ${itk-module}TestDriver 57 | --with-threads 80 58 | --compare DATA{Baseline/itkSLICImageFilterTest1Baseline.nii} 59 | ${TEMP}/itkSLICImageFilterTest2Output.nii 60 | itkSLICImageFilterTest 61 | DATA{Input/VM1111Shrink-LAB.mha} 62 | ${TEMP}/itkSLICImageFilterTest2Output.nii 25 ) 63 | 64 | itk_add_test(NAME itkSLICImageFilterTest_3 65 | COMMAND ${itk-module}TestDriver 66 | --compare DATA{Baseline/itkSLICImageFilterTest3Baseline.nii} 67 | ${TEMP}/itkSLICImageFilterTest3Output.nii 68 | itkSLICImageFilterTest 69 | DATA{Input/cthead1.png} 70 | ${TEMP}/itkSLICImageFilterTest3Output.nii 20 ) 71 | 72 | 73 | itk_add_test(NAME itkSLICImageFilterTest2 74 | COMMAND ${itk-module}TestDriver 75 | itkSLICImageFilterTest2 ) 76 | 77 | # 78 | # GTest based tests 79 | # 80 | 81 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../CMake") 82 | 83 | option(USE_SYSTEM_GTEST "Use system installed gtest" ${ITK_USE_SYSTEM_LIBRARIES}) 84 | mark_as_advanced(USE_SYSTEM_GTEST) 85 | if(NOT USE_SYSTEM_GTEST) 86 | include(External_GTest) 87 | include(UseGTest) 88 | link_directories("${GTEST_LIBRARIES_DIR}") 89 | else() 90 | find_package( GTest ) 91 | endif() 92 | 93 | # we always include CMake's GTest to get the gtest_add_tests method 94 | 95 | set(${itk-module}GTests 96 | itkSliceImageFilterTest.cxx 97 | itkFunctorsTest.cxx 98 | ) 99 | 100 | add_executable(${itk-module}GTestDriver ${${itk-module}GTests}) 101 | 102 | if(NOT USE_SYSTEM_GTEST) 103 | add_dependencies(${itk-module}GTestDriver GTest) 104 | endif() 105 | add_dependencies(${itk-module}-all ${itk-module}GTestDriver) 106 | 107 | target_link_libraries(${itk-module}GTestDriver 108 | ${${itk-module}-Test_LIBRARIES} 109 | ${GTEST_BOTH_LIBRARIES} 110 | ) 111 | 112 | target_include_directories(${itk-module}GTestDriver PRIVATE 113 | ${GTEST_INCLUDE_DIRS}) 114 | 115 | gtest_add_tests(${itk-module}GTestDriver "" ${${itk-module}GTests}) 116 | -------------------------------------------------------------------------------- /include/itkHessianImageFilter.h: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkHessianImageFilter_h 19 | #define itkHessianImageFilter_h 20 | 21 | #include "itkImage.h" 22 | #include "itkImageToImageFilter.h" 23 | #include "itkSymmetricSecondRankTensor.h" 24 | 25 | namespace itk 26 | { 27 | 28 | /** 29 | * \class HessianImageFilter 30 | * \brief Computes the Hessian matrix of an image by central differences 31 | * 32 | * This filter directly computes the derivatives of an image for 33 | * the Hessian and does not convolve with a Gaussian kernel. 34 | * 35 | * \sa HessianRecursiveGaussianImageFilter 36 | * \sa SmoothingRecursiveGaussianImageFilter 37 | * 38 | * \ingroup Streamed 39 | * \ingroup SimpleITKFiltersModule 40 | */ 41 | template ::RealType, 44 | TInputImage::ImageDimension >, 45 | TInputImage::ImageDimension > > 46 | class HessianImageFilter : 47 | public ImageToImageFilter< TInputImage, TOutputImage> 48 | { 49 | public: 50 | 51 | /** Standard typedefs */ 52 | typedef HessianImageFilter Self; 53 | typedef ImageToImageFilter Superclass; 54 | typedef SmartPointer Pointer; 55 | typedef SmartPointer ConstPointer; 56 | 57 | 58 | /** Pixel Type of the input image */ 59 | typedef TInputImage InputImageType; 60 | typedef typename InputImageType::PixelType PixelType; 61 | 62 | /** Type of the output Image */ 63 | typedef TOutputImage OutputImageType; 64 | typedef typename OutputImageType::PixelType OutputPixelType; 65 | typedef typename OutputImageType::RegionType OutputImageRegionType; 66 | 67 | 68 | /** Run-time type information (and related methods). */ 69 | itkTypeMacro( HessianImageFilter, ImageToImageFilter ); 70 | 71 | /** Method for creation through the object factory. */ 72 | itkNewMacro(Self); 73 | 74 | virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; 75 | 76 | 77 | #ifdef ITK_USE_CONCEPT_CHECKING 78 | /** Begin concept checking */ 79 | itkConceptMacro(InputHasNumericTraitsCheck, 80 | (Concept::HasNumericTraits)); 81 | itkConceptMacro(OutputHasPixelTraitsCheck, 82 | (Concept::HasPixelTraits)); 83 | /** End concept checking */ 84 | #endif 85 | 86 | protected: 87 | 88 | HessianImageFilter( void ); 89 | 90 | void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId) ITK_OVERRIDE; 91 | 92 | private: 93 | 94 | HessianImageFilter(const Self&); //purposely not implemented 95 | void operator=(const Self&); //purposely not implemented 96 | 97 | }; 98 | 99 | } // end namespace itk 100 | 101 | 102 | #ifndef ITK_MANUAL_INSTANTIATION 103 | #include "itkHessianImageFilter.hxx" 104 | #endif 105 | 106 | 107 | #endif //itkHessianImageFilter_h 108 | -------------------------------------------------------------------------------- /test/itkSLICImageFilterTest.cxx: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #include "itkSLICImageFilter.h" 20 | #include "itkVectorImage.h" 21 | #include "itkImageFileReader.h" 22 | #include "itkImageFileWriter.h" 23 | #include "itkTimeProbe.h" 24 | 25 | namespace 26 | { 27 | 28 | template 29 | void itkSLICImageFilter(const std::string &inFileName, 30 | const std::string &outFileName, 31 | const unsigned int gridSize, 32 | const float proximityWeight) 33 | { 34 | 35 | typedef TImageType InputImageType; 36 | typedef itk::Image OutputImageType; 37 | 38 | typedef itk::ImageFileReader ReaderType; 39 | typename ReaderType::Pointer reader = ReaderType::New(); 40 | reader->SetFileName(inFileName); 41 | 42 | typedef itk::SLICImageFilter< InputImageType, OutputImageType > FilterType; 43 | typename FilterType::Pointer filter = FilterType::New(); 44 | filter->SetInput(reader->GetOutput()); 45 | filter->SetSuperGridSize(gridSize); 46 | filter->DebugOn(); 47 | filter->SetSpatialProximityWeight(proximityWeight); 48 | 49 | reader->Update(); 50 | 51 | itk::TimeProbe clock; 52 | clock.Start(); 53 | filter->Update(); 54 | clock.Stop(); 55 | 56 | std::cout << "Total: " << clock.GetTotal() << std::endl; 57 | 58 | 59 | typedef itk::ImageFileWriter WriterType; 60 | typename WriterType::Pointer writer = WriterType::New(); 61 | writer->SetFileName(outFileName); 62 | writer->SetInput(filter->GetOutput()); 63 | writer->Update(); 64 | 65 | filter->Print(std::cout); 66 | 67 | } 68 | } 69 | 70 | int itkSLICImageFilterTest(int argc, char *argv[]) 71 | { 72 | if (argc < 3) 73 | { 74 | std::cerr << "Expected inFileName outFileName [gridSize]\n"; 75 | return EXIT_FAILURE; 76 | } 77 | 78 | 79 | const unsigned int gridSize = (argc > 3) ? atoi(argv[3] ) : 20; 80 | const float proximityWeight = (argc > 4) ? atof(argv[4] ) : 10.0; 81 | const char *inFileName = argv[1]; 82 | const char *outFileName = argv[2]; 83 | 84 | const unsigned int VDimension = 2; 85 | typedef itk::VectorImage InputImageType; 86 | 87 | typedef itk::ImageFileReader ReaderType; 88 | ReaderType::Pointer reader = ReaderType::New(); 89 | reader->SetFileName(inFileName); 90 | reader->UpdateOutputInformation(); 91 | 92 | const unsigned int Dimension = reader->GetImageIO()->GetNumberOfDimensions(); 93 | const unsigned int Components = reader->GetImageIO()->GetNumberOfComponents(); 94 | switch (Dimension) 95 | { 96 | case 1: 97 | case 2: 98 | if ( Components == 1 ) 99 | { 100 | itkSLICImageFilter< itk::Image >(inFileName, outFileName, gridSize, proximityWeight); 101 | } 102 | else 103 | { 104 | itkSLICImageFilter< itk::VectorImage >(inFileName, outFileName, gridSize, proximityWeight); 105 | } 106 | break; 107 | case 3: 108 | if ( Components == 1 ) 109 | { 110 | itkSLICImageFilter< itk::Image >(inFileName, outFileName, gridSize, proximityWeight); 111 | } 112 | else 113 | { 114 | itkSLICImageFilter< itk::VectorImage >(inFileName, outFileName, gridSize, proximityWeight); 115 | } 116 | break; 117 | default: 118 | std::cerr << "Unsupported Dimensions: " << Dimension << std::endl; 119 | return EXIT_FAILURE; 120 | } 121 | return 0; 122 | } 123 | -------------------------------------------------------------------------------- /include/itkObjectnessMeasureImageFilter.hxx: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkObjectnessMeasureImageFilter_hxx 19 | #define itkObjectnessMeasureImageFilter_hxx 20 | 21 | #include "itkObjectnessMeasureImageFilter.h" 22 | #include "itkHessianImageFilter.h" 23 | #include "itkHessianToObjectnessMeasureImageFilter.h" 24 | #include "itkProgressAccumulator.h" 25 | 26 | 27 | namespace itk 28 | { 29 | 30 | template< typename TInputImage, typename TOutputImage > 31 | ObjectnessMeasureImageFilter< TInputImage,TOutputImage > 32 | ::ObjectnessMeasureImageFilter() : 33 | m_Alpha( 0.5 ), 34 | m_Beta( 0.5 ), 35 | m_Gamma( 5.0 ), 36 | m_ObjectDimension( 1 ), 37 | m_BrightObject( true ), 38 | m_ScaleObjectnessMeasure( true ) 39 | { 40 | } 41 | 42 | template< typename TInputImage, typename TOutputImage > 43 | ObjectnessMeasureImageFilter< TInputImage,TOutputImage > 44 | ::~ObjectnessMeasureImageFilter() 45 | { 46 | } 47 | 48 | 49 | template< typename TInputImage, typename TOutputImage > 50 | void 51 | ObjectnessMeasureImageFilter< TInputImage,TOutputImage > 52 | ::EnlargeOutputRequestedRegion(DataObject *output) 53 | { 54 | output->SetRequestedRegionToLargestPossibleRegion(); 55 | } 56 | 57 | template< typename TInputImage, typename TOutputImage > 58 | void 59 | ObjectnessMeasureImageFilter< TInputImage,TOutputImage > 60 | ::GenerateData() 61 | { 62 | // Create a process accumulator for tracking the progress of this minipipeline 63 | ProgressAccumulator::Pointer progress = ProgressAccumulator::New(); 64 | progress->SetMiniPipelineFilter( this ); 65 | 66 | typename InputImageType::Pointer localInput = InputImageType::New(); 67 | localInput->Graft( this->GetInput() ); 68 | 69 | typedef HessianImageFilter HessianFilterType; 70 | typedef typename HessianFilterType::OutputImageType HessianImageType; 71 | 72 | typename HessianFilterType::Pointer hessianFilter = HessianFilterType::New(); 73 | 74 | hessianFilter->SetInput( localInput ); 75 | 76 | typedef HessianToObjectnessMeasureImageFilter< HessianImageType, OutputImageType > ObjectnessFilterType; 77 | 78 | typename ObjectnessFilterType::Pointer objectnessFilter = ObjectnessFilterType::New(); 79 | 80 | objectnessFilter->SetInput( hessianFilter->GetOutput() ); 81 | 82 | objectnessFilter->SetAlpha( m_Alpha ); 83 | objectnessFilter->SetBeta( m_Beta ); 84 | objectnessFilter->SetGamma( m_Gamma ); 85 | objectnessFilter->SetScaleObjectnessMeasure( m_ScaleObjectnessMeasure ); 86 | objectnessFilter->SetObjectDimension( m_ObjectDimension ); 87 | objectnessFilter->SetBrightObject( m_BrightObject); 88 | 89 | progress->RegisterInternalFilter( hessianFilter, 0.5f ); 90 | progress->RegisterInternalFilter( objectnessFilter, 0.5f ); 91 | 92 | 93 | objectnessFilter->GraftOutput( this->GetOutput() ); 94 | objectnessFilter->Update(); 95 | this->GraftOutput(objectnessFilter->GetOutput()); 96 | } 97 | 98 | template< typename TInputImage, typename TOutputImage > 99 | void 100 | ObjectnessMeasureImageFilter< TInputImage,TOutputImage > 101 | ::PrintSelf(std::ostream & os, Indent indent) const 102 | { 103 | Superclass::PrintSelf(os, indent); 104 | 105 | os << indent << "Alpha: " << m_Alpha << std::endl; 106 | os << indent << "Beta: " << m_Beta << std::endl; 107 | os << indent << "Gamma: " << m_Gamma << std::endl; 108 | os << indent << "ScaleObjectnessMeasure: " << m_ScaleObjectnessMeasure << std::endl; 109 | os << indent << "ObjectDimension: " << m_ObjectDimension << std::endl; 110 | os << indent << "BrightObject: " << m_BrightObject << std::endl; 111 | } 112 | 113 | } 114 | #endif // itkObjectnessMeasureImageFilter_hxx 115 | -------------------------------------------------------------------------------- /include/itkObjectnessMeasureImageFilter.h: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkObjectnessMeasureImageFilter_h 19 | #define itkObjectnessMeasureImageFilter_h 20 | 21 | #include "itkImageToImageFilter.h" 22 | 23 | namespace itk 24 | { 25 | /** \class ObjectnessMeasureImageFilter 26 | * 27 | * This is a composite filter which combines a computation of the 28 | * hessian with computation of the objectness. 29 | * 30 | * \ingroup SimpleITKFiltersModule 31 | */ 32 | template< typename TInputImage, typename TOutputImage > 33 | class ObjectnessMeasureImageFilter 34 | : public ImageToImageFilter< TInputImage, TOutputImage > 35 | { 36 | public: 37 | /** Standard class typedefs. */ 38 | typedef ObjectnessMeasureImageFilter Self; 39 | 40 | typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass; 41 | 42 | typedef SmartPointer< Self > Pointer; 43 | typedef SmartPointer< const Self > ConstPointer; 44 | 45 | typedef typename Superclass::InputImageType InputImageType; 46 | typedef typename Superclass::OutputImageType OutputImageType; 47 | 48 | typedef double InternalType; 49 | 50 | /** Image dimension */ 51 | itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension); 52 | 53 | 54 | /** Method for creation through the object factory. */ 55 | itkNewMacro(Self); 56 | 57 | /** Runtime information support. */ 58 | itkTypeMacro(ObjectnessMeasureImageFilter, ImageToImageFilter); 59 | 60 | 61 | /** Set/Get Alpha, the weight corresponding to R_A 62 | * (the ratio of the smallest eigenvalue that has to be large to the larger ones). 63 | * Smaller values lead to increased sensitivity to the object dimensionality. */ 64 | itkSetMacro(Alpha, double); 65 | itkGetConstMacro(Alpha, double); 66 | 67 | /** Set/Get Beta, the weight corresponding to R_B 68 | * (the ratio of the largest eigenvalue that has to be small to the larger ones). 69 | * Smaller values lead to increased sensitivity to the object dimensionality. */ 70 | itkSetMacro(Beta, double); 71 | itkGetConstMacro(Beta, double); 72 | 73 | /** Set/Get Gamma, the weight corresponding to S 74 | * (the Frobenius norm of the Hessian matrix, or second-order structureness) */ 75 | itkSetMacro(Gamma, double); 76 | itkGetConstMacro(Gamma, double); 77 | 78 | /** Toggle scaling the objectness measure with the magnitude of the largest 79 | absolute eigenvalue */ 80 | itkSetMacro(ScaleObjectnessMeasure, bool); 81 | itkGetConstMacro(ScaleObjectnessMeasure, bool); 82 | itkBooleanMacro(ScaleObjectnessMeasure); 83 | 84 | /** Set/Get the dimensionality of the object (0: points (blobs), 85 | * 1: lines (vessels), 2: planes (plate-like structures), 3: hyper-planes. 86 | * ObjectDimension must be smaller than ImageDimension. */ 87 | itkSetMacro(ObjectDimension, unsigned int); 88 | itkGetConstMacro(ObjectDimension, unsigned int); 89 | 90 | /** Enhance bright structures on a dark background if true, the opposite if 91 | false. */ 92 | itkSetMacro(BrightObject, bool); 93 | itkGetConstMacro(BrightObject, bool); 94 | itkBooleanMacro(BrightObject); 95 | 96 | 97 | protected: 98 | ObjectnessMeasureImageFilter(); 99 | 100 | ~ObjectnessMeasureImageFilter(); 101 | 102 | 103 | void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; 104 | 105 | virtual void GenerateData() ITK_OVERRIDE; 106 | 107 | void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; 108 | 109 | private: 110 | ObjectnessMeasureImageFilter(const Self&); //purposely not implemented 111 | void operator=(const Self&); //purposely not implemented 112 | 113 | double m_Alpha; 114 | double m_Beta; 115 | double m_Gamma; 116 | unsigned int m_ObjectDimension; 117 | bool m_BrightObject; 118 | bool m_ScaleObjectnessMeasure; 119 | 120 | }; 121 | 122 | } 123 | 124 | 125 | #ifndef ITK_MANUAL_INSTANTIATION 126 | #include "itkObjectnessMeasureImageFilter.hxx" 127 | #endif 128 | 129 | #endif // itkObjectnessMeasureImageFilter_h 130 | -------------------------------------------------------------------------------- /CMake/External_GTest.cmake: -------------------------------------------------------------------------------- 1 | include(ExternalProject) 2 | 3 | # Make sure this file is included only once 4 | get_filename_component(CMAKE_CURRENT_LIST_FILENAME ${CMAKE_CURRENT_LIST_FILE} NAME_WE) 5 | if(${CMAKE_CURRENT_LIST_FILENAME}_FILE_INCLUDED) 6 | return() 7 | endif() 8 | set(${CMAKE_CURRENT_LIST_FILENAME}_FILE_INCLUDED 1) 9 | 10 | set(proj GTest) 11 | 12 | set(GTEST_TARGET_VERSION 1.7.0) 13 | set(GTEST_DOWNLOAD_SOURCE_HASH "2d6ec8ccdf5c46b05ba54a9fd1d130d7") 14 | 15 | # follow the standard EP_PREFIX locations 16 | set(GTEST_binary_dir ${CMAKE_CURRENT_BINARY_DIR}/${proj}-prefix/src/${proj}-build) 17 | set(GTEST_source_dir ${CMAKE_CURRENT_BINARY_DIR}/${proj}-prefix/src/${proj}) 18 | set(GTEST_install_dir ${CMAKE_CURRENT_BINARY_DIR}/${proj}) 19 | 20 | set(${proj}_ARCHIVE_OUTPUT_DIRECTORY "/lib") 21 | if (CMAKE_GENERATOR MATCHES "Visual Studio") 22 | set(${proj}_ARCHIVE_OUTPUT_DIRECTORY "/lib/$") 23 | endif() 24 | 25 | # 26 | # Function which converts a list a cmake cache variable into a list of 27 | # "-Dvar:type=value;" suitable for command line initialization. 28 | # 29 | function( VariableListToArgs var_list args ) 30 | foreach( var IN LISTS ${var_list} ) 31 | if( DEFINED ${var} AND NOT ${var} STREQUAL "" ) # if variable has been set 32 | get_property( type CACHE ${var} PROPERTY TYPE ) 33 | if (NOT "${type}" STREQUAL "") 34 | set(type ":${type}") 35 | else() 36 | set(type ":UNINITIALIZED") 37 | endif() 38 | set(value ${${var}}) 39 | STRING( REPLACE ";" "$" value "${value}" ) 40 | list( APPEND _args "-D${var}${type}=${value}" ) 41 | endif() 42 | endforeach() 43 | set( ${args} "${_args}" PARENT_SCOPE) 44 | endfunction( ) 45 | 46 | 47 | if(MSVC_VERSION EQUAL 1700) 48 | # Tuples are limited by _VARIADIC_MAX in VS11. The variadic 49 | # templates are not deep enough by default. We are not currently 50 | # using the GTest features which require tuple, so just disable them 51 | # and hope that upstream premanetly addresses the problem, with out 52 | # required more CMake core for compiler issues. 53 | set(CMAKE_CXX_FLAGS "-DGTEST_HAS_TR1_TUPLE=0 ${CMAKE_CXX_FLAGS}") 54 | endif() 55 | 56 | list( APPEND ep_common_list 57 | CMAKE_BUILD_TYPE 58 | CMAKE_MAKE_PROGRAM 59 | 60 | CMAKE_C_COMPILER 61 | CMAKE_C_COMPILER_ARG1 62 | 63 | CMAKE_C_FLAGS 64 | CMAKE_C_FLAGS_DEBUG 65 | CMAKE_C_FLAGS_MINSIZEREL 66 | CMAKE_C_FLAGS_RELEASE 67 | CMAKE_C_FLAGS_RELWITHDEBINFO 68 | 69 | CMAKE_CXX_COMPILER 70 | CMAKE_CXX_COMPILER_ARG1 71 | 72 | CMAKE_CXX_FLAGS 73 | CMAKE_CXX_FLAGS_DEBUG 74 | CMAKE_CXX_FLAGS_MINSIZEREL 75 | CMAKE_CXX_FLAGS_RELEASE 76 | CMAKE_CXX_FLAGS_RELWITHDEBINFO 77 | 78 | CMAKE_LINKER 79 | 80 | CMAKE_EXE_LINKER_FLAGS 81 | CMAKE_EXE_LINKER_FLAGS_DEBUG 82 | CMAKE_EXE_LINKER_FLAGS_MINSIZEREL 83 | CMAKE_EXE_LINKER_FLAGS_RELEASE 84 | CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO 85 | CMAKE_MODULE_LINKER_FLAGS 86 | CMAKE_MODULE_LINKER_FLAGS_DEBUG 87 | CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL 88 | CMAKE_MODULE_LINKER_FLAGS_RELEASE 89 | CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO 90 | CMAKE_SHARED_LINKER_FLAGS 91 | CMAKE_SHARED_LINKER_FLAGS_DEBUG 92 | CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL 93 | CMAKE_SHARED_LINKER_FLAGS_RELEASE 94 | CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO 95 | 96 | CMAKE_PREFIX_PATH 97 | CMAKE_FRAMEWORK_PATH 98 | CMAKE_SYSTEM_PREFIX_PATH 99 | CMAKE_SYSTEM_INCLUDE_PATH 100 | CMAKE_SYSTEM_LIBRARY_PATH 101 | CMAKE_SYSTEM_PROGRAM_PATH 102 | CMAKE_SYSTEM_IGNORE_PATH 103 | 104 | CMAKE_GENERATOR 105 | CMAKE_EXTRA_GENERATOR 106 | ) 107 | 108 | if( APPLE ) 109 | list( APPEND ep_common_list 110 | CMAKE_OSX_SYSROOT 111 | CMAKE_OSX_DEPLOYMENT_TARGET 112 | CMAKE_OSX_ARCHITECTURES ) 113 | endif() 114 | 115 | 116 | VariableListToArgs( ep_common_list ep_common_args ) 117 | 118 | set(ep_extra_args) 119 | 120 | if(MSVC) 121 | set(ep_extra_args ${ep_extra_args} -Dgtest_force_shared_crt:BOOL=ON) 122 | endif() 123 | 124 | 125 | ExternalProject_Add(${proj} 126 | URL "https://midas3.kitware.com/midas/download/item/318120/gtest-1.7.0.zip" 127 | URL_MD5 ${GTEST_DOWNLOAD_SOURCE_HASH} 128 | INSTALL_DIR ${GTEST_install_dir} 129 | CMAKE_GENERATOR ${gen} 130 | CMAKE_ARGS 131 | --no-warn-unused-cli 132 | CMAKE_CACHE_ARGS 133 | ${ep_common_args} 134 | ${ep_extra_args} 135 | -Dgtest_disable_pthreads:BOOL=ON 136 | -DBUILD_SHARED_LIBS:BOOL=OFF 137 | -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=/lib 138 | INSTALL_COMMAND 139 | ${CMAKE_COMMAND} -E copy_directory ${${proj}_ARCHIVE_OUTPUT_DIRECTORY} /lib 140 | COMMAND 141 | ${CMAKE_COMMAND} -E copy_directory /include /include 142 | ) 143 | 144 | 145 | set(GTEST_ROOT ${GTEST_install_dir}) 146 | set(GTEST_INCLUDE_DIRS "${GTEST_install_dir}/include") 147 | set(GTEST_LIBRARIES_DIR "${GTEST_install_dir}/lib/") 148 | set(GTEST_LIBRARIES "gtest") 149 | set(GTEST_MAIN_LIBRARIES "gtest_main") 150 | set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) 151 | 152 | -------------------------------------------------------------------------------- /include/itkHessianImageFilter.hxx: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkHessianImageFilter_hxx 19 | #define itkHessianImageFilter_hxx 20 | 21 | 22 | #include "itkHessianImageFilter.h" 23 | 24 | #include "itkImageRegionConstIterator.h" 25 | #include "itkImageRegionIterator.h" 26 | #include "itkNeighborhoodAlgorithm.h" 27 | 28 | #include "itkProgressReporter.h" 29 | #include "itkProgressAccumulator.h" 30 | 31 | namespace itk 32 | { 33 | 34 | /** 35 | * Constructor 36 | */ 37 | 38 | template 39 | HessianImageFilter 40 | ::HessianImageFilter( void ) 41 | { 42 | } 43 | 44 | /** 45 | * Enlarge Input Requested Region 46 | */ 47 | template< class TInputImage, class TOutputImage > 48 | void 49 | HessianImageFilter< TInputImage, TOutputImage > 50 | ::GenerateInputRequestedRegion() 51 | { 52 | // call the superclass' implementation of this method. this should 53 | // copy the output requested region to the input requested region 54 | Superclass::GenerateInputRequestedRegion(); 55 | 56 | // get pointers to the input and output 57 | typename InputImageType::Pointer inputPtr = 58 | const_cast< TInputImage * >( this->GetInput() ); 59 | 60 | if ( !inputPtr ) 61 | { 62 | return; 63 | } 64 | 65 | 66 | // the hessaion just needs a 1 radius neighborhood 67 | const unsigned int radius = 1; 68 | 69 | // get a copy of the input requested region (should equal the output 70 | // requested region) 71 | typename TInputImage::RegionType inputRequestedRegion; 72 | inputRequestedRegion = inputPtr->GetRequestedRegion(); 73 | 74 | // pad the input requested region by the operator radius 75 | inputRequestedRegion.PadByRadius( radius ); 76 | 77 | // crop the input requested region at the input's largest possible region 78 | if ( inputRequestedRegion.Crop( inputPtr->GetLargestPossibleRegion() ) ) 79 | { 80 | inputPtr->SetRequestedRegion(inputRequestedRegion); 81 | return; 82 | } 83 | else 84 | { 85 | // Couldn't crop the region (requested region is outside the largest 86 | // possible region). Throw an exception. 87 | 88 | // store what we tried to request (prior to trying to crop) 89 | inputPtr->SetRequestedRegion(inputRequestedRegion); 90 | 91 | // build an exception 92 | InvalidRequestedRegionError e(__FILE__, __LINE__); 93 | e.SetLocation(ITK_LOCATION); 94 | e.SetDescription("Requested region is (at least partially) outside the largest possible region."); 95 | e.SetDataObject(inputPtr); 96 | throw e; 97 | } 98 | } 99 | 100 | /** 101 | * Threaded Data Generation 102 | */ 103 | template 104 | void 105 | HessianImageFilter 106 | ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, 107 | ThreadIdType threadId) 108 | { 109 | ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels() ); 110 | 111 | const TInputImage *input = this->GetInput(); 112 | 113 | const unsigned int ImageDimension = TInputImage::ImageDimension; 114 | 115 | TOutputImage *output = this->GetOutput(); 116 | 117 | 118 | typedef typename OutputImageType::PixelType HessianType; 119 | ImageRegionIterator oit; 120 | 121 | itk::Size radius; 122 | radius.Fill( 1 ); 123 | unsigned long center; 124 | unsigned long stride[ImageDimension]; 125 | 126 | typename TInputImage::SpacingType spacing = input->GetSpacing(); 127 | 128 | 129 | // compute the boundary faces of our region 130 | typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator< TInputImage >::FaceListType faceList; 131 | NeighborhoodAlgorithm::ImageBoundaryFacesCalculator< TInputImage > bC; 132 | faceList = bC( input, outputRegionForThread, radius ); 133 | 134 | typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator< TInputImage >::FaceListType::iterator fit; 135 | 136 | typedef ConstNeighborhoodIterator< TInputImage > NeighborhoodType; 137 | 138 | // get center and dimension strides for iterator neighborhoods 139 | NeighborhoodType it( radius, input, *faceList.begin() ); 140 | center = it.Size()/2; 141 | for ( unsigned int i = 0; i < ImageDimension; ++i ) 142 | { 143 | stride[i] = it.GetStride(i); 144 | } 145 | 146 | // process each of the region "faces" 147 | for ( fit = faceList.begin(); fit != faceList.end(); ++fit ) 148 | { 149 | // set up the iterator for the "face" and let the automatic 150 | // boundary condition detection work as needed 151 | it = NeighborhoodType( radius, input, *fit); 152 | 153 | oit = ImageRegionIterator( output, *fit ); 154 | 155 | while ( !it.IsAtEnd() ) 156 | { 157 | // symetric hessian 158 | HessianType H; 159 | 160 | 161 | //Calculate 2nd order derivative on the diaganal 162 | for ( unsigned int i = 0; i < ImageDimension; i++ ) 163 | { 164 | H(i,i) = it.GetPixel(center + stride[i]) + it.GetPixel(center - stride[i]) 165 | - 2.0 * it.GetPixel(center); 166 | H(i,i) /= spacing[i] * spacing[i]; 167 | } 168 | 169 | //Calculate the 2nd derivatives 170 | for ( unsigned int i = 0; i < ImageDimension - 1; i++ ) 171 | { 172 | for ( unsigned int j = i + 1; j < ImageDimension; j++ ) 173 | { 174 | H(i,j) = ( it.GetPixel(center - stride[i] - stride[j]) 175 | - it.GetPixel(center - stride[i] + stride[j]) 176 | - it.GetPixel(center + stride[i] - stride[j]) 177 | + it.GetPixel(center + stride[i] + stride[j]) 178 | ) / ( 4.0 * spacing[i] * spacing[j] ); 179 | } 180 | } 181 | 182 | oit.Set( H ); 183 | 184 | ++oit; 185 | ++it; 186 | progress.CompletedPixel(); 187 | } 188 | } 189 | 190 | } 191 | 192 | } // end namespace itk 193 | 194 | #endif // itkHessianImageFilter_hxx 195 | -------------------------------------------------------------------------------- /include/itkSliceImageFilter.h: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkSliceImageFilter_h 19 | #define itkSliceImageFilter_h 20 | 21 | #include "itkImageToImageFilter.h" 22 | 23 | namespace itk 24 | { 25 | /** \class SliceImageFilter 26 | * \brief Slices an image based on a starting index and a stopping 27 | * index, and a step size. 28 | * 29 | * This class is designed to facilitate the implementation of extended 30 | * sliced based indexing into images. 31 | * 32 | * The input and output image must be of the same dimension. 33 | * 34 | * The input parameters are a starting and stopping index as well as a 35 | * stepping size. The staring index indicates the first pixels to 36 | * used and for each dimension the index is incremented by the step 37 | * until the index is equal to or "beyond" the stopping index. If the 38 | * step is negative then the image will be revered in the dimension, 39 | * and the stopping index is expected to be less then the starting 40 | * index. If the stopping index is already beyond the starting then a 41 | * image of zero size will be returned. 42 | * 43 | * The output image's starting index is always zero. The origin is the 44 | * physical location of the starting index. The output directions 45 | * cosine matrix is that of the input but with sign changes matching 46 | * that of the step's sign. 47 | * 48 | * \note In certain combination such as with start=1, and step>1 while 49 | * the physical location of the center of the pixel remains the same, 50 | * the extent (edge to edge space) of the pixel will beyond the extent 51 | * of the original image. 52 | * 53 | * \ingroup GeometricTransform Streamed 54 | * \ingroup SimpleITKFiltersModule 55 | */ 56 | template< class TInputImage, class TOutputImage > 57 | class ITK_EXPORT SliceImageFilter: 58 | public ImageToImageFilter< TInputImage, TOutputImage > 59 | { 60 | public: 61 | /** Standard class typedefs. */ 62 | typedef SliceImageFilter Self; 63 | typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass; 64 | typedef SmartPointer< Self > Pointer; 65 | typedef SmartPointer< const Self > ConstPointer; 66 | 67 | /** Method for creation through the object factory. */ 68 | itkNewMacro(Self); 69 | 70 | /** Run-time type information (and related methods). */ 71 | itkTypeMacro(SliceImageFilter, ImageToImageFilter); 72 | 73 | /** Typedef to images */ 74 | typedef TOutputImage OutputImageType; 75 | typedef TInputImage InputImageType; 76 | typedef typename OutputImageType::Pointer OutputImagePointer; 77 | typedef typename InputImageType::Pointer InputImagePointer; 78 | typedef typename InputImageType::ConstPointer InputImageConstPointer; 79 | 80 | typedef typename TOutputImage::IndexType OutputIndexType; 81 | typedef typename TInputImage::IndexType InputIndexType; 82 | typedef typename TOutputImage::OffsetType OutputOffsetType; 83 | 84 | /** Typedef to describe the output image region type. */ 85 | typedef typename TOutputImage::RegionType OutputImageRegionType; 86 | 87 | /** ImageDimension enumeration. */ 88 | itkStaticConstMacro(ImageDimension, unsigned int, 89 | TInputImage::ImageDimension); 90 | itkStaticConstMacro(OutputImageDimension, unsigned int, 91 | TOutputImage::ImageDimension); 92 | 93 | 94 | typedef typename InputImageType::IndexType IndexType; 95 | typedef typename InputIndexType::IndexValueType IndexValueType; 96 | typedef FixedArray< int, ImageDimension > ArrayType; 97 | 98 | /** Set/Get the first index extracted from the input image */ 99 | itkSetMacro(Start, IndexType); 100 | itkGetConstReferenceMacro(Start, IndexType); 101 | void SetStart(IndexValueType start); 102 | 103 | /** Set/Get the excluded end of the range */ 104 | itkSetMacro(Stop, IndexType); 105 | itkGetConstReferenceMacro(Stop, IndexType); 106 | void SetStop(IndexValueType stop); 107 | 108 | /** Set/Get the stride of indexes extracted 109 | * 110 | * An exception will be generated if 0. 111 | */ 112 | itkSetMacro(Step, ArrayType); 113 | itkGetConstReferenceMacro(Step, ArrayType); 114 | void SetStep( int step); 115 | 116 | /** SliceImageFilter produces an image which is a different 117 | * resolution and with a different pixel spacing than its input 118 | * image. 119 | * \sa ProcessObject::GenerateOutputInformaton() */ 120 | virtual void GenerateOutputInformation() ITK_OVERRIDE; 121 | 122 | virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; 123 | 124 | #ifdef ITK_USE_CONCEPT_CHECKING 125 | /** Begin concept checking */ 126 | itkConceptMacro( InputConvertibleToOutputCheck, 127 | ( Concept::Convertible< typename TInputImage::PixelType, typename TOutputImage::PixelType > ) ); 128 | itkConceptMacro( SameDimensionCheck, 129 | ( Concept::SameDimension< ImageDimension, OutputImageDimension > ) ); 130 | /** End concept checking */ 131 | #endif 132 | 133 | protected: 134 | SliceImageFilter(); 135 | ~SliceImageFilter() {} 136 | void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; 137 | 138 | /** SliceImageFilter can be implemented as a multithreaded filter. 139 | * Therefore, this implementation provides a ThreadedGenerateData() routine 140 | * which is called for each processing thread. The output image data is 141 | * allocated automatically by the superclass prior to calling 142 | * ThreadedGenerateData(). ThreadedGenerateData can only write to the 143 | * portion of the output image specified by the parameter 144 | * "outputRegionForThread" 145 | * 146 | * \sa ImageToImageFilter::ThreadedGenerateData(), 147 | * ImageToImageFilter::GenerateData() */ 148 | void ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, 149 | ThreadIdType threadId) ITK_OVERRIDE; 150 | 151 | void VerifyInputInformation() ITK_OVERRIDE; 152 | 153 | private: 154 | SliceImageFilter(const Self &); //purposely not implemented 155 | void operator=(const Self &); //purposely not implemented 156 | 157 | IndexType m_Start; 158 | IndexType m_Stop; 159 | ArrayType m_Step; 160 | }; 161 | } // end namespace itk 162 | 163 | #ifndef ITK_MANUAL_INSTANTIATION 164 | #include "itkSliceImageFilter.hxx" 165 | #endif 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /include/itkSLICImageFilter.h: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkSLICImageFilter_h 19 | #define itkSLICImageFilter_h 20 | 21 | #include "itkImageToImageFilter.h" 22 | #include "itkIsSame.h" 23 | 24 | #include "itkBarrier.h" 25 | 26 | 27 | #include "itkImageRegionConstIteratorWithIndex.h" 28 | #include "itkImageScanlineIterator.h" 29 | 30 | #include "itkMath.h" 31 | 32 | namespace itk 33 | { 34 | 35 | /** \class SLICImageFilter 36 | * \brief Simple Linear Iterative Clustering (SLIC) Superpixel algorithm 37 | * 38 | * The Simple Linear Iterative Clustering (SLIC) Superpixel performs 39 | * joint domain ( image intensity and physical location ) clustering 40 | * of the input image to form a superpixel labeled output image. 41 | * 42 | * This implementation is multi-threaded, works in n-dimensions with 43 | * m-component images. The filter works with VectorImage, scalar 44 | * Images, and Images of FixedArrays. 45 | * 46 | * R. Achanta, A. Shaji, K. Smith, and A. Lucchi. Slic superpixels. Technical report, 2010. 47 | * 48 | * \ingroup SimpleITKFiltersModule 49 | */ 50 | template< typename TInputImage, typename TOutputImage, typename TDistancePixel = float> 51 | class SLICImageFilter: 52 | public ImageToImageFilter< TInputImage, TOutputImage > 53 | { 54 | public: 55 | /** Standard class typedefs. */ 56 | typedef SLICImageFilter Self; 57 | typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass; 58 | typedef SmartPointer< Self > Pointer; 59 | typedef SmartPointer< const Self > ConstPointer; 60 | 61 | /** Method for creation through the object factory. */ 62 | itkNewMacro(Self); 63 | 64 | /** Run-time type information (and related methods). */ 65 | itkTypeMacro(SLICImageFilter, ImageToImageFilter); 66 | 67 | /** Image type information. */ 68 | typedef TInputImage InputImageType; 69 | typedef typename InputImageType::PixelType InputPixelType; 70 | typedef TOutputImage OutputImageType; 71 | typedef typename OutputImageType::PixelType LabelPixelType; 72 | itkStaticConstMacro(ImageDimension, unsigned int, TInputImage::ImageDimension); 73 | typedef TDistancePixel DistanceType; 74 | typedef Image DistanceImageType; 75 | typedef signed char MarkerPixelType; 76 | typedef Image MarkerImageType; 77 | 78 | typedef typename InputImageType::IndexType IndexType; 79 | typedef typename InputImageType::PointType PointType; 80 | // assume variable length vector right now 81 | typedef double ClusterComponentType; 82 | typedef vnl_vector ClusterType; 83 | typedef vnl_vector_ref RefClusterType; 84 | 85 | typedef typename OutputImageType::RegionType OutputImageRegionType; 86 | 87 | typedef FixedArray< unsigned int, ImageDimension > SuperGridSizeType; 88 | 89 | /** \brief Weighting coefficient for the spatial distance 90 | * 91 | * The default value is 10. This default is useful for the CIE 92 | * L*a*b*, which often has component range of [0,100], +/-100, 93 | * +/-100. This value can be adjusted based on the range of the 94 | * pixel space. 95 | */ 96 | itkSetMacro( SpatialProximityWeight, double ); 97 | itkGetConstMacro( SpatialProximityWeight, double ); 98 | 99 | /** \brief Number of cluster iteration to perform. 100 | */ 101 | itkSetMacro( MaximumNumberOfIterations, unsigned int ); 102 | itkGetConstMacro( MaximumNumberOfIterations, unsigned int ); 103 | 104 | /** \brief Size in pixel of the expected cluster size. 105 | * 106 | * The value can be anisotropic to provide a scaling weight 107 | * per-dimension for the special proximity. 108 | */ 109 | itkSetMacro(SuperGridSize, SuperGridSizeType); 110 | void SetSuperGridSize(unsigned int factor); 111 | void SetSuperGridSize(unsigned int i, unsigned int factor); 112 | 113 | /** \brief Enable additional step to clean disconnected labels. 114 | * 115 | * Relabel super grid labels to remove isolated components. 116 | */ 117 | itkSetMacro(LabelConnectivityEnforce, bool); 118 | itkGetMacro(LabelConnectivityEnforce, bool); 119 | itkBooleanMacro(LabelConnectivityEnforce); 120 | 121 | /** \brief Minimum size of an independent components. 122 | * 123 | * This value is expressed as a ratio of the size of the component 124 | * to the super grid size. The default is 0.25. 125 | * 126 | * When LabelConnectivity is enforced, any component smaller than 127 | * this size if relabels the same as a neighboring component. Larger 128 | * components are given a new label. 129 | */ 130 | itkSetMacro(LabelConnectivityMinimumSize, float); 131 | itkGetMacro(LabelConnectivityMinimumSize, float); 132 | 133 | /** \brief Sequentially label the cluster components. 134 | * 135 | * False by default. 136 | * 137 | * The sequential algorithm is single threaded. 138 | */ 139 | itkSetMacro(LabelConnectivityRelabelSequential, bool); 140 | itkGetMacro(LabelConnectivityRelabelSequential, bool); 141 | itkBooleanMacro(LabelConnectivityRelabelSequential); 142 | 143 | protected: 144 | SLICImageFilter(); 145 | ~SLICImageFilter(); 146 | 147 | void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; 148 | 149 | void VerifyInputInformation () ITK_OVERRIDE; 150 | 151 | /** Generate full output and require full input */ 152 | void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; 153 | 154 | void BeforeThreadedGenerateData() ITK_OVERRIDE; 155 | 156 | void ThreadedUpdateDistanceAndLabel(const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId); 157 | 158 | void ThreadedUpdateClusters(const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId); 159 | 160 | void ThreadedPerturbClusters(const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId); 161 | 162 | void ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId) ITK_OVERRIDE; 163 | 164 | void AfterThreadedGenerateData() ITK_OVERRIDE; 165 | 166 | size_t RelabelClusterAndMark(const IndexType &idx, 167 | LabelPixelType label, 168 | MarkerPixelType fill=0, 169 | LabelPixelType outLabel=0); 170 | 171 | DistanceType Distance(const ClusterType &cluster1, 172 | const ClusterType &cluster2); 173 | 174 | inline DistanceType Distance(const ClusterType &cluster, 175 | const InputPixelType &v, 176 | const IndexType &idx) 177 | { 178 | return Self::DistanceDispatched(cluster, v, idx); 179 | } 180 | 181 | inline static void CreateClusterPoint( const InputPixelType &v, 182 | ClusterType &outCluster, 183 | const unsigned int numberOfComponents, 184 | const IndexType &idx ) 185 | { 186 | NumericTraits::AssignToArray(v, outCluster); 187 | for(unsigned int i = 0; i < ImageDimension; ++i) 188 | { 189 | outCluster[numberOfComponents+i] = idx[i]; 190 | } 191 | } 192 | 193 | private: 194 | SLICImageFilter(const Self &); //purposely not implemented 195 | void operator=(const Self &); //purposely not implemented 196 | 197 | template 198 | inline DistanceType DistanceDispatched(const ClusterType &cluster, 199 | const TPixelType &v, 200 | const IndexType &idx) 201 | { 202 | const unsigned int s = cluster.size(); 203 | double d1 = 0.0; 204 | double d2 = 0.0; 205 | unsigned int i = 0; 206 | for (; i::ValueType &v, 225 | const IndexType &idx ) 226 | { 227 | double d1 = 0.0; 228 | double d2 = 0.0; 229 | unsigned int i = 0; 230 | { 231 | const double d = (cluster[i] - v); 232 | d1 += d*d; 233 | } 234 | i = 1; 235 | for (unsigned int j = 0; j < ImageDimension; ++j, ++i) 236 | { 237 | const double d = (cluster[i] - idx[j]) * m_DistanceScales[j]; 238 | d2 += d*d; 239 | } 240 | d2 *= m_SpatialProximityWeight * m_SpatialProximityWeight; 241 | 242 | return d1+d2; 243 | } 244 | 245 | 246 | SuperGridSizeType m_SuperGridSize; 247 | unsigned int m_MaximumNumberOfIterations; 248 | double m_SpatialProximityWeight; 249 | bool m_LabelConnectivityEnforce; 250 | float m_LabelConnectivityMinimumSize; 251 | bool m_LabelConnectivityRelabelSequential; 252 | 253 | FixedArray m_DistanceScales; 254 | std::vector m_Clusters; 255 | std::vector m_OldClusters; 256 | 257 | struct UpdateCluster 258 | { 259 | size_t count; 260 | vnl_vector cluster; 261 | }; 262 | 263 | typedef std::map UpdateClusterMap; 264 | 265 | std::vector m_UpdateClusterPerThread; 266 | 267 | std::vector > m_MissedLabelsPerThread; 268 | 269 | ThreadIdType m_NumberOfThreadsUsed; 270 | 271 | typename Barrier::Pointer m_Barrier; 272 | typename DistanceImageType::Pointer m_DistanceImage; 273 | typename MarkerImageType::Pointer m_MarkerImage; 274 | }; 275 | } // end namespace itk 276 | 277 | #ifndef ITK_MANUAL_INSTANTIATION 278 | #include "itkSLICImageFilter.hxx" 279 | #endif 280 | 281 | #endif //itkSLICImageFilter_h 282 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /include/itkSliceImageFilter.hxx: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | * 20 | * Portions of this file are subject to the VTK Toolkit Version 3 copyright. 21 | * 22 | * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 23 | * 24 | * For complete copyright, license and disclaimer of warranty information 25 | * please refer to the NOTICE file at the top of the ITK source tree. 26 | * 27 | *=========================================================================*/ 28 | #ifndef itkSliceImageFilter_hxx 29 | #define itkSliceImageFilter_hxx 30 | 31 | #include "itkSliceImageFilter.h" 32 | #include "itkImageRegionIteratorWithIndex.h" 33 | #include "itkContinuousIndex.h" 34 | #include "itkObjectFactory.h" 35 | #include "itkProgressReporter.h" 36 | 37 | namespace itk 38 | { 39 | /** 40 | * 41 | */ 42 | template< class TInputImage, class TOutputImage > 43 | SliceImageFilter< TInputImage, TOutputImage > 44 | ::SliceImageFilter() 45 | { 46 | m_Start.Fill(NumericTraits::min()); 47 | m_Stop.Fill(NumericTraits::max()); 48 | m_Step.Fill(1); 49 | } 50 | 51 | /** 52 | * 53 | */ 54 | template< class TInputImage, class TOutputImage > 55 | void 56 | SliceImageFilter< TInputImage, TOutputImage > 57 | ::PrintSelf(std::ostream & os, Indent indent) const 58 | { 59 | Superclass::PrintSelf(os, indent); 60 | 61 | os << indent << "Start: " << m_Start << std::endl; 62 | os << indent << "Stop: " << m_Stop << std::endl; 63 | os << indent << "Step: " << m_Step << std::endl; 64 | 65 | } 66 | 67 | /** 68 | * 69 | */ 70 | template< class TInputImage, class TOutputImage > 71 | void 72 | SliceImageFilter< TInputImage, TOutputImage > 73 | ::SetStart( typename TInputImage::IndexType::IndexValueType start) 74 | { 75 | unsigned int j; 76 | 77 | for ( j = 0; j < ImageDimension; j++ ) 78 | { 79 | if ( start != m_Start[j] ) 80 | { 81 | this->Modified(); 82 | m_Start.Fill( start ); 83 | return; 84 | } 85 | } 86 | } 87 | 88 | 89 | /** 90 | * 91 | */ 92 | template< class TInputImage, class TOutputImage > 93 | void 94 | SliceImageFilter< TInputImage, TOutputImage > 95 | ::SetStop(typename TInputImage::IndexType::IndexValueType stop) 96 | { 97 | unsigned int j; 98 | 99 | for ( j = 0; j < ImageDimension; j++ ) 100 | { 101 | if ( stop != m_Stop[j] ) 102 | { 103 | this->Modified(); 104 | m_Stop.Fill( stop ); 105 | return; 106 | } 107 | } 108 | } 109 | 110 | 111 | /** 112 | * 113 | */ 114 | template< class TInputImage, class TOutputImage > 115 | void 116 | SliceImageFilter< TInputImage, TOutputImage > 117 | ::SetStep(int step) 118 | { 119 | unsigned int j; 120 | 121 | for ( j = 0; j < ImageDimension; j++ ) 122 | { 123 | if ( step != m_Step[j] ) 124 | { 125 | this->Modified(); 126 | m_Step.Fill( step ); 127 | return; 128 | } 129 | } 130 | 131 | } 132 | 133 | /** 134 | * 135 | */ 136 | template< class TInputImage, class TOutputImage > 137 | void 138 | SliceImageFilter< TInputImage, TOutputImage > 139 | ::ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, 140 | ThreadIdType threadId) 141 | { 142 | // Get the input and output pointers 143 | InputImageConstPointer inputPtr = this->GetInput(); 144 | OutputImagePointer outputPtr = this->GetOutput(); 145 | 146 | // Support progress methods/callbacks 147 | ProgressReporter progress( this, threadId, outputRegionForThread.GetNumberOfPixels() ); 148 | 149 | const typename TInputImage::SizeType &inputSize = inputPtr->GetLargestPossibleRegion().GetSize(); 150 | const typename TInputImage::IndexType &inputIndex = inputPtr->GetLargestPossibleRegion().GetIndex(); 151 | 152 | // clamp start 153 | InputIndexType start; 154 | for ( unsigned int i = 0; i < TOutputImage::ImageDimension; i++ ) 155 | { 156 | start[i] = std::max( m_Start[i], inputIndex[i] ); 157 | start[i] = std::min( start[i], static_cast(inputIndex[i] + inputSize[i]-1) ); 158 | } 159 | 160 | // Define/declare an iterator that will walk the output region for this 161 | // thread. 162 | typedef ImageRegionIteratorWithIndex< TOutputImage > OutputIterator; 163 | OutputIterator outIt(outputPtr, outputRegionForThread); 164 | 165 | OutputIndexType destIndex; 166 | InputIndexType srcIndex; 167 | 168 | while ( !outIt.IsAtEnd() ) 169 | { 170 | // Determine the index and physical location of the output pixel 171 | destIndex = outIt.GetIndex(); 172 | 173 | 174 | for( unsigned int i = 0; i < TOutputImage::ImageDimension; ++i ) 175 | { 176 | srcIndex[i] = destIndex[i]*m_Step[i] + start[i]; 177 | } 178 | 179 | // Copy the input pixel to the output 180 | outIt.Set( inputPtr->GetPixel(srcIndex) ); 181 | ++outIt; 182 | 183 | progress.CompletedPixel(); 184 | } 185 | } 186 | 187 | /** 188 | * 189 | */ 190 | template< class TInputImage, class TOutputImage > 191 | void 192 | SliceImageFilter< TInputImage, TOutputImage > 193 | ::GenerateInputRequestedRegion() 194 | { 195 | 196 | 197 | // Get pointers to the input and output 198 | InputImagePointer inputPtr = const_cast< TInputImage * >( this->GetInput() ); 199 | OutputImagePointer outputPtr = this->GetOutput(); 200 | 201 | const typename TOutputImage::SizeType & outputRequestedRegionSize = outputPtr->GetRequestedRegion().GetSize(); 202 | const typename TOutputImage::IndexType & outputRequestedRegionStartIndex = outputPtr->GetRequestedRegion().GetIndex(); 203 | 204 | const typename TInputImage::SizeType &inputSize = inputPtr->GetLargestPossibleRegion().GetSize(); 205 | const typename TInputImage::IndexType &inputIndex = inputPtr->GetLargestPossibleRegion().GetIndex(); 206 | 207 | // clamp start 208 | InputIndexType start; 209 | for ( unsigned int i = 0; i < TOutputImage::ImageDimension; i++ ) 210 | { 211 | // clamp to valid index range and don't include one past end, so 212 | // that a zero size RR would be valid 213 | start[i] = std::max( m_Start[i], inputIndex[i] ); 214 | start[i] = std::min( start[i], static_cast(inputIndex[i] + inputSize[i] -1) ); 215 | } 216 | 217 | 218 | typename TInputImage::SizeType inputRequestedRegionSize; 219 | inputRequestedRegionSize.Fill(0); 220 | for ( unsigned int i=0; i < TInputImage::ImageDimension; ++i ) 221 | { 222 | if ( outputRequestedRegionSize[i] > 0 ) 223 | { 224 | inputRequestedRegionSize[i] = (outputRequestedRegionSize[i] - 1 ) * vnl_math_abs(m_Step[i]) + 1; 225 | } 226 | } 227 | 228 | InputIndexType inputRequestedRegionIndex; 229 | for ( unsigned int i=0; i < TOutputImage::ImageDimension; ++i ) 230 | { 231 | inputRequestedRegionIndex[i] = outputRequestedRegionStartIndex[i] * m_Step[i] + start[i]; 232 | 233 | // if reversing, go to the lower ending index - 1 234 | if (m_Step[i] < 0) 235 | { 236 | inputRequestedRegionIndex[i] -= inputRequestedRegionSize[i] - 1; 237 | } 238 | } 239 | 240 | 241 | typename TInputImage::RegionType inputRequestedRegion; 242 | inputRequestedRegion.SetIndex(inputRequestedRegionIndex); 243 | inputRequestedRegion.SetSize(inputRequestedRegionSize); 244 | 245 | // test if input RR is completely inside input largest region 246 | if ( inputRequestedRegion.GetNumberOfPixels() > 0 && 247 | !inputPtr->GetLargestPossibleRegion().IsInside( inputRequestedRegion ) ) 248 | { 249 | itkExceptionMacro( "Logic Error: incorrect computation of RequestedRegion" ); 250 | } 251 | 252 | inputPtr->SetRequestedRegion(inputRequestedRegion); 253 | return; 254 | 255 | } 256 | 257 | /** 258 | * 259 | */ 260 | template< class TInputImage, class TOutputImage > 261 | void 262 | SliceImageFilter< TInputImage, TOutputImage > 263 | ::GenerateOutputInformation() 264 | { 265 | // Call the superclass' implementation of this method 266 | Superclass::GenerateOutputInformation(); 267 | 268 | // Get pointers to the input and output 269 | InputImageConstPointer inputPtr = this->GetInput(); 270 | OutputImagePointer outputPtr = this->GetOutput(); 271 | 272 | // Compute the output spacing, the output image size, and the 273 | // output image start index 274 | const typename TInputImage::SpacingType &inputSpacing = inputPtr->GetSpacing(); 275 | const typename TInputImage::SizeType &inputSize = inputPtr->GetLargestPossibleRegion().GetSize(); 276 | const typename TInputImage::IndexType &inputIndex = inputPtr->GetLargestPossibleRegion().GetIndex(); 277 | typename TInputImage::IndexType inputStartIndex; 278 | 279 | typename TOutputImage::SpacingType outputSpacing; 280 | typename TOutputImage::SizeType outputSize; 281 | 282 | typename TOutputImage::IndexType outputStartIndex; 283 | outputStartIndex.Fill(0); 284 | 285 | for ( unsigned int i = 0; i < TOutputImage::ImageDimension; i++ ) 286 | { 287 | outputSpacing[i] = inputSpacing[i] * vnl_math_abs(m_Step[i]); 288 | 289 | // clamp start 290 | // Based on the sign of the step include 1 after the end. 291 | IndexValueType start = std::max( m_Start[i], inputIndex[i] - int(m_Step[i]<0)); 292 | start = std::min( start, static_cast(inputIndex[i] + inputSize[i]) - int(m_Step[i]<0) ); 293 | 294 | // clamp stop 295 | // Based on the sign of the step include 1 after the end. 296 | IndexValueType stop = std::max( m_Stop[i], inputIndex[i] - int(m_Step[i]<0) ); 297 | stop = std::min( stop, static_cast(inputIndex[i] + inputSize[i]) - int(m_Step[i]<0)); 298 | 299 | // If both the numerator and the denominator have the same sign, 300 | // then the range is a valid and non-zero sized. Truncation is the 301 | // correct rounding for these positive values. 302 | if ( (m_Step[i] > 0 && stop > start) || 303 | ( m_Step[i] < 0 && stop < start ) ) 304 | { 305 | outputSize[i] = (stop-start)/m_Step[i]; 306 | } 307 | else 308 | { 309 | outputSize[i] = 0u; 310 | } 311 | 312 | // If the step is negative, then the start is still the index of 313 | // the output origin 314 | inputStartIndex[i] = start; 315 | 316 | } 317 | 318 | const typename TInputImage::DirectionType & inputDirection = inputPtr->GetDirection(); 319 | typename TInputImage::DirectionType flipMatrix; 320 | 321 | // Need a matrix to model the reversing of directions, this should 322 | // maintain the physical location of the pixels 323 | for ( unsigned int j = 0; j < ImageDimension; j++ ) 324 | { 325 | flipMatrix[j][j] = (m_Step[j]>0) ? 1.0 : -1.0; 326 | } 327 | 328 | outputPtr->SetDirection(inputDirection * flipMatrix); 329 | outputPtr->SetSpacing(outputSpacing); 330 | 331 | typename TOutputImage::PointType outputOrigin; 332 | inputPtr->TransformIndexToPhysicalPoint(inputStartIndex, outputOrigin); 333 | outputPtr->SetOrigin(outputOrigin); 334 | 335 | // Set region 336 | typename TOutputImage::RegionType outputLargestPossibleRegion; 337 | outputLargestPossibleRegion.SetSize(outputSize); 338 | outputLargestPossibleRegion.SetIndex(outputStartIndex); 339 | 340 | outputPtr->SetLargestPossibleRegion(outputLargestPossibleRegion); 341 | } 342 | 343 | template< class TInputImage, class TOutputImage > 344 | void 345 | SliceImageFilter< TInputImage, TOutputImage > 346 | ::VerifyInputInformation() 347 | { 348 | 349 | Superclass::VerifyInputInformation(); 350 | 351 | for ( unsigned int i = 0; i < ImageDimension; ++i ) 352 | { 353 | if ( m_Step[i] == 0 ) 354 | { 355 | itkExceptionMacro( "Step size is zero " << m_Step << "!" ); 356 | } 357 | } 358 | 359 | } 360 | 361 | } // end namespace itk 362 | 363 | #endif 364 | -------------------------------------------------------------------------------- /test/itkSliceImageFilterTest.cxx: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #include 20 | 21 | #include "gtest/gtest.h" 22 | 23 | #include "itkPhysicalPointImageSource.h" 24 | #include "itkGaussianImageSource.h" 25 | #include "itkImageRegionConstIterator.h" 26 | 27 | 28 | // This test verifies the principle that the SliceImageFilter should 29 | // not change the physical location of the signal. This is done by 30 | // constructing an image of points, each corresponding to the phycical 31 | // location of the center of the voxel, then verifying that the value 32 | // still matches the physcial location. 33 | 34 | namespace 35 | { 36 | 37 | // This function checks that all values in an image are equivalent to 38 | // the physical point of the image. 39 | template 40 | bool CheckValueIsPhysicalPoint( const TImageType *img ) 41 | { 42 | 43 | typedef itk::ImageRegionConstIterator IteratorType; 44 | IteratorType it(img, img->GetBufferedRegion() ); 45 | 46 | bool match = true; 47 | 48 | typename TImageType::PointType pt; 49 | img->TransformIndexToPhysicalPoint( it.GetIndex(), pt ); 50 | while( !it.IsAtEnd() ) 51 | { 52 | for ( unsigned int i = 0; i < TImageType::ImageDimension; ++i ) 53 | { 54 | img->TransformIndexToPhysicalPoint( it.GetIndex(), pt ); 55 | 56 | EXPECT_DOUBLE_EQ( pt[i], it.Get()[i] ) << "Index: " << it.GetIndex() << " Point: " << pt << " Value: " << it.Get() << std::endl, match = false; 57 | } 58 | 59 | ++it; 60 | } 61 | return match; 62 | } 63 | 64 | template 65 | typename TImageType::Pointer RunFilter( const TImageType *img, 66 | typename TImageType::IndexType start, 67 | typename TImageType::IndexType stop, 68 | int step[TImageType::ImageDimension] 69 | ) 70 | { 71 | typedef itk::SliceImageFilter FilterType; 72 | typename FilterType::Pointer sliceFilter = FilterType::New(); 73 | 74 | sliceFilter->SetInput( img ); 75 | sliceFilter->SetStart( start ); 76 | sliceFilter->SetStop( stop ); 77 | sliceFilter->SetStep( step ); 78 | sliceFilter->UpdateLargestPossibleRegion(); 79 | 80 | return sliceFilter->GetOutput(); 81 | } 82 | 83 | 84 | } 85 | 86 | TEST(SliceImageFilterTests, PhysicalPoint1) 87 | { 88 | const unsigned int ImageDimension = 2; 89 | typedef itk::Point PixelType; 90 | typedef itk::Image ImageType; 91 | 92 | typedef itk::PhysicalPointImageSource SourceType; 93 | SourceType::Pointer source = SourceType::New(); 94 | 95 | 96 | // these size are chossen as a power of two and a prime number. 97 | SourceType::SizeValueType size[] = {128,127}; 98 | source->SetSize( size ); 99 | 100 | float origin[] = {1.1f, 2.22f}; 101 | source->SetOrigin( origin ); 102 | 103 | 104 | int step[ImageDimension]; 105 | ImageType::IndexType start; 106 | ImageType::IndexType stop; 107 | stop[0] = size[0]; 108 | stop[1] = size[1]; 109 | 110 | for( start[0] = 0; start[0] < 10; ++start[0] ) 111 | for( start[1] = 0; start[1] < 10; ++start[1] ) 112 | for( step[0] = 1; step[0] < 10; ++step[0] ) 113 | for( step[1] = 1; step[1] < 10; ++step[1] ) 114 | { 115 | 116 | ImageType::Pointer img; 117 | 118 | img = RunFilter( source->GetOutput(), start, stop, step ); 119 | 120 | EXPECT_TRUE( CheckValueIsPhysicalPoint( img.GetPointer() ) ) << "== Failed - step:" << step[0] << " " << step[1] << " start: " < PixelType; 129 | typedef itk::Image ImageType; 130 | 131 | typedef itk::PhysicalPointImageSource SourceType; 132 | SourceType::Pointer source = SourceType::New(); 133 | 134 | 135 | // these size are chossen as a power of two and a prime number. 136 | SourceType::SizeValueType size[] = {128,127}; 137 | source->SetSize( size ); 138 | 139 | float origin[] = {3.33f, 4.4444f}; 140 | source->SetOrigin( origin ); 141 | 142 | 143 | int step[ImageDimension] = {3,4}; 144 | ImageType::IndexType start; 145 | ImageType::IndexType stop; 146 | 147 | ASSERT_TRUE(size[0] > 10); 148 | ASSERT_TRUE(size[1] > 10); 149 | 150 | for( start[0] = 0; start[0] < 10; ++start[0] ) 151 | for( start[1] = 0; start[1] < 10; ++start[1] ) 152 | for( stop[0] = size[0]; stop[0] > (ImageType::IndexValueType)(size[0] - 10); --stop[0] ) 153 | for( stop[1] = size[1]; stop[1] > (ImageType::IndexValueType)(size[1] -10); --stop[1] ) 154 | { 155 | 156 | ImageType::Pointer img; 157 | 158 | img = RunFilter( source->GetOutput(), start, stop, step ); 159 | 160 | EXPECT_TRUE( CheckValueIsPhysicalPoint( img.GetPointer() ) ) 161 | << "== Failed - step:" << step[0] << " " << step[1] 162 | << " start: " << start[0] << " " << start[1] 163 | << " stop: " << stop[0] << " " << stop[1] 164 | << std::endl; 165 | } 166 | 167 | } 168 | 169 | 170 | TEST(SliceImageFilterTests, PhysicalPoint3) 171 | { 172 | const unsigned int ImageDimension = 2; 173 | typedef itk::Point PixelType; 174 | typedef itk::Image ImageType; 175 | 176 | typedef itk::PhysicalPointImageSource SourceType; 177 | SourceType::Pointer source = SourceType::New(); 178 | 179 | 180 | // these size are chossen as a power of two and a prime number. 181 | SourceType::SizeValueType size[] = {16,17}; 182 | source->SetSize( size ); 183 | 184 | float origin[] = {3.33f, 4.4444f}; 185 | source->SetOrigin( origin ); 186 | 187 | int step[ImageDimension] = {-2,-2}; 188 | ImageType::IndexType start; 189 | ImageType::IndexType stop; 190 | 191 | for( start[0] = 10; start[0] < 20; ++start[0] ) 192 | for( start[1] = 10; start[1] < 20; ++start[1] ) 193 | for( stop[0] = -5; stop[0] > 12; --stop[0] ) 194 | for( stop[1] = -5; stop[1] > 12; --stop[1] ) 195 | { 196 | 197 | ImageType::Pointer img; 198 | 199 | img = RunFilter( source->GetOutput(), start, stop, step ); 200 | 201 | EXPECT_TRUE( CheckValueIsPhysicalPoint( img.GetPointer() ) ) 202 | << "== Failed - step:" << step[0] << " " << step[1] 203 | << " start: " < PixelType; 214 | typedef itk::Image ImageType; 215 | 216 | typedef itk::PhysicalPointImageSource SourceType; 217 | SourceType::Pointer source = SourceType::New(); 218 | 219 | 220 | // these size are chossen as a power of two and a prime number. 221 | SourceType::SizeValueType size[] = {32,32}; 222 | source->SetSize( size ); 223 | 224 | int step[ImageDimension] = {1,1}; 225 | ImageType::IndexType start; 226 | start.Fill( 10 ); 227 | ImageType::IndexType stop; 228 | stop.Fill( 10 ); 229 | 230 | 231 | ImageType::Pointer img; 232 | 233 | img = RunFilter( source->GetOutput(), start, stop, step ); 234 | std::cout << img; 235 | 236 | for( unsigned int i = 0; i < ImageDimension; ++i) 237 | { 238 | EXPECT_EQ( 0u, img->GetLargestPossibleRegion().GetSize()[i] ); 239 | } 240 | 241 | start[0] = 2; 242 | start[1] = 2; 243 | stop[0] = 10; 244 | stop[1] = 2; 245 | 246 | img = RunFilter( source->GetOutput(), start, stop, step ); 247 | 248 | EXPECT_EQ( 8u, img->GetLargestPossibleRegion().GetSize()[0] ); 249 | EXPECT_EQ( 0u, img->GetLargestPossibleRegion().GetSize()[1] ); 250 | 251 | } 252 | 253 | TEST(SliceImageFilterTests,Coverage) 254 | { 255 | const unsigned int ImageDimension = 3; 256 | typedef itk::Image ImageType; 257 | 258 | typedef itk::SliceImageFilter FilterType; 259 | 260 | FilterType::Pointer filter = FilterType::New(); 261 | std::cout << filter; 262 | 263 | FilterType::IndexType idx; 264 | idx.Fill( 10 ); 265 | 266 | filter->SetStart(idx); 267 | EXPECT_EQ( idx, filter->GetStart() ); 268 | 269 | idx.Fill(11); 270 | filter->SetStart(11); 271 | EXPECT_EQ( idx, filter->GetStart() ); 272 | 273 | idx.Fill(12); 274 | filter->SetStop(idx); 275 | EXPECT_EQ( idx, filter->GetStop() ); 276 | 277 | idx.Fill(13); 278 | filter->SetStop(13); 279 | EXPECT_EQ( idx, filter->GetStop() ); 280 | 281 | FilterType::ArrayType a; 282 | a.Fill(14); 283 | filter->SetStep(a); 284 | EXPECT_EQ( a, filter->GetStep() ); 285 | 286 | a.Fill(15); 287 | filter->SetStep(15); 288 | EXPECT_EQ(a, filter->GetStep() ); 289 | } 290 | 291 | TEST(SliceImageFilterTests,Sizes) 292 | { 293 | const unsigned int ImageDimension = 3; 294 | typedef itk::Image ImageType; 295 | 296 | typedef itk::GaussianImageSource SourceType; 297 | SourceType::Pointer source = SourceType::New(); 298 | 299 | SourceType::SizeType size = {{64,64,64}}; 300 | source->SetSize(size); 301 | source->ReleaseDataFlagOn(); 302 | 303 | typedef itk::SliceImageFilter FilterType; 304 | 305 | FilterType::Pointer filter = FilterType::New(); 306 | filter->SetInput( source->GetOutput() ); 307 | // check with default start, stop, step 308 | EXPECT_NO_THROW(filter->Update()); 309 | EXPECT_EQ(filter->GetOutput()->GetLargestPossibleRegion().GetSize(), size) << "Check full size for defaults"; 310 | 311 | 312 | filter = FilterType::New(); 313 | filter->SetInput( source->GetOutput() ); 314 | filter->SetStart( 64 ); 315 | filter->SetStop(-1); 316 | filter->SetStep(-1); 317 | EXPECT_NO_THROW(filter->Update()); 318 | EXPECT_EQ(filter->GetOutput()->GetLargestPossibleRegion().GetSize(), size) << "Check full size for negative step"; 319 | 320 | std::cout << "Filter size: " << filter->GetOutput()->GetLargestPossibleRegion() << std::endl; 321 | std::cout << "Filter buffered size: " << filter->GetOutput()->GetBufferedRegion() << std::endl; 322 | std::cout << "Input size: " << size << std::endl; 323 | } 324 | 325 | TEST(SliceImageFilterTests,ExceptionalCases) 326 | { 327 | const unsigned int ImageDimension = 3; 328 | typedef itk::Image ImageType; 329 | 330 | typedef itk::GaussianImageSource SourceType; 331 | SourceType::Pointer source = SourceType::New(); 332 | 333 | 334 | typedef itk::SliceImageFilter FilterType; 335 | 336 | FilterType::Pointer filter = FilterType::New(); 337 | filter->SetInput( source->GetOutput() ); 338 | 339 | filter->SetStep( 0 ); 340 | EXPECT_ANY_THROW( filter->Update() ) << "Check with 0 step"; 341 | 342 | // for some reason after the above exception, the pipeline is not 343 | // clean, and Verify input information will not get executed again, 344 | // so just create a new filter... 345 | filter = FilterType::New(); 346 | filter->SetInput( source->GetOutput() ); 347 | filter->SetStart(10000); 348 | filter->SetStop(10001); 349 | EXPECT_NO_THROW( filter->Update() ) << "Check with over-sized start stop are clamped to zero"; 350 | EXPECT_EQ( 0u, filter->GetOutput()->GetLargestPossibleRegion().GetNumberOfPixels() ); 351 | 352 | 353 | filter = FilterType::New(); 354 | filter->SetInput( source->GetOutput() ); 355 | filter->SetStart(12); 356 | filter->SetStop(10); 357 | EXPECT_NO_THROW( filter->Update() ) << "Check stop is clamped"; 358 | EXPECT_EQ( 0u, filter->GetOutput()->GetLargestPossibleRegion().GetNumberOfPixels() ); 359 | 360 | 361 | filter = FilterType::New(); 362 | filter->SetInput( source->GetOutput() ); 363 | filter->SetStart(-12); 364 | filter->SetStop(-10); 365 | EXPECT_NO_THROW( filter->Update() ) << "Check undersized start and stop"; 366 | EXPECT_EQ( 0u, filter->GetOutput()->GetLargestPossibleRegion().GetNumberOfPixels() ); 367 | 368 | filter = FilterType::New(); 369 | filter->SetInput( source->GetOutput() ); 370 | filter->SetStart(-12); 371 | filter->SetStop(-10); 372 | filter->SetStep(-1); 373 | EXPECT_NO_THROW( filter->Update() ) << "Check undersized start and stop"; 374 | EXPECT_EQ( 0u, filter->GetOutput()->GetLargestPossibleRegion().GetNumberOfPixels() ); 375 | 376 | } 377 | -------------------------------------------------------------------------------- /include/itkSLICImageFilter.hxx: -------------------------------------------------------------------------------- 1 | /*========================================================================= 2 | * 3 | * Copyright Insight Software Consortium 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0.txt 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 | #ifndef itkSLICImageFilter_hxx 19 | #define itkSLICImageFilter_hxx 20 | 21 | #include "itkSLICImageFilter.h" 22 | 23 | 24 | #include "itkConstNeighborhoodIterator.h" 25 | #include "itkImageRegionIterator.h" 26 | #include 27 | #include 28 | 29 | 30 | namespace itk 31 | { 32 | 33 | template 34 | SLICImageFilter 35 | ::SLICImageFilter() 36 | : m_MaximumNumberOfIterations( (ImageDimension > 2) ? 5 : 10), 37 | m_SpatialProximityWeight( 10.0 ), 38 | m_LabelConnectivityEnforce(true), 39 | m_LabelConnectivityMinimumSize(0.25), 40 | m_LabelConnectivityRelabelSequential(false), 41 | m_NumberOfThreadsUsed(1), 42 | m_Barrier(Barrier::New()) 43 | { 44 | m_SuperGridSize.Fill(50); 45 | } 46 | 47 | template 48 | SLICImageFilter 49 | ::~SLICImageFilter() 50 | { 51 | } 52 | 53 | 54 | template 55 | void 56 | SLICImageFilter 57 | ::SetSuperGridSize(unsigned int factor) 58 | { 59 | unsigned int i; 60 | for (i = 0; i < ImageDimension; ++i) 61 | { 62 | if (factor != m_SuperGridSize[i]) 63 | { 64 | break; 65 | } 66 | } 67 | if ( i < ImageDimension ) 68 | { 69 | this->Modified(); 70 | m_SuperGridSize.Fill(factor); 71 | } 72 | } 73 | 74 | template 75 | void 76 | SLICImageFilter 77 | ::SetSuperGridSize(unsigned int i, unsigned int factor) 78 | { 79 | if (m_SuperGridSize[i] == factor) 80 | { 81 | return; 82 | } 83 | 84 | this->Modified(); 85 | m_SuperGridSize[i] = factor; 86 | } 87 | 88 | template 89 | void 90 | SLICImageFilter 91 | ::PrintSelf(std::ostream & os, Indent indent) const 92 | { 93 | Superclass::PrintSelf(os, indent); 94 | os << indent << "SuperGridSize: " << m_SuperGridSize << std::endl; 95 | os << indent << "MaximumNumberOfIterations: " << m_MaximumNumberOfIterations << std::endl; 96 | os << indent << "SpatialProximityWeight: " << m_SpatialProximityWeight << std::endl; 97 | os << indent << "LabelConnectivityEnforce: " << m_LabelConnectivityEnforce << std::endl; 98 | os << indent << "LabelConnectivityMinimumSize: " << m_LabelConnectivityMinimumSize << std::endl; 99 | os << indent << "LabelConnectivityRelabelSequential: " << m_LabelConnectivityRelabelSequential << std::endl; 100 | } 101 | 102 | template 103 | void 104 | SLICImageFilter 105 | ::VerifyInputInformation () 106 | { 107 | Superclass::VerifyInputInformation(); 108 | 109 | const InputImageType *inputImage = this->GetInput(); 110 | 111 | typename InputImageType::SizeType size = inputImage->GetLargestPossibleRegion().GetSize(); 112 | 113 | size_t numberOfClusters = 1u; 114 | 115 | for ( unsigned int i = 0; i < ImageDimension; ++i ) 116 | { 117 | numberOfClusters *= Math::Ceil( double(size[i])/m_SuperGridSize[i] ); 118 | } 119 | 120 | if (numberOfClusters >= static_cast(itk::NumericTraits::max())) 121 | { 122 | itkExceptionMacro( "Too many clusters for output pixel type!" ); 123 | } 124 | 125 | } 126 | 127 | template 128 | void 129 | SLICImageFilter 130 | ::EnlargeOutputRequestedRegion(DataObject *output) 131 | { 132 | Superclass::EnlargeOutputRequestedRegion(output); 133 | output->SetRequestedRegionToLargestPossibleRegion(); 134 | } 135 | 136 | 137 | template 138 | void 139 | SLICImageFilter 140 | ::BeforeThreadedGenerateData() 141 | { 142 | itkDebugMacro("Starting BeforeThreadedGenerateData"); 143 | 144 | 145 | // Compute actual number of threads used 146 | { 147 | ThreadIdType numberOfThreads = this->GetNumberOfThreads(); 148 | 149 | if ( itk::MultiThreader::GetGlobalMaximumNumberOfThreads() != 0 ) 150 | { 151 | numberOfThreads = std::min( this->GetNumberOfThreads(), itk::MultiThreader::GetGlobalMaximumNumberOfThreads() ); 152 | } 153 | 154 | typename TOutputImage::RegionType splitRegion; // dummy region - just to call the following method 155 | 156 | m_NumberOfThreadsUsed = this->SplitRequestedRegion(0, numberOfThreads, splitRegion); 157 | } 158 | 159 | m_Barrier->Initialize(m_NumberOfThreadsUsed); 160 | 161 | const InputImageType *inputImage = this->GetInput(); 162 | 163 | 164 | itkDebugMacro("Initializing Clusters"); 165 | 166 | 167 | typename InputImageType::SizeType strips, size, totalErr, accErr; 168 | typename InputImageType::IndexType startIdx, idx; 169 | 170 | typename InputImageType::RegionType region = inputImage->GetLargestPossibleRegion(); 171 | 172 | size = region.GetSize(); 173 | 174 | for ( unsigned int i = 0; i < ImageDimension; ++i ) 175 | { 176 | // number of super pixels 177 | strips[i] = size[i]/m_SuperGridSize[i]; 178 | 179 | // the remainder of the pixels 180 | totalErr[i] = size[i]%m_SuperGridSize[i]; 181 | 182 | // the starting superpixel index 183 | if (strips[i] != 0) 184 | { 185 | startIdx[i] = region.GetIndex()[i]+m_SuperGridSize[i]/2 + totalErr[i]/(strips[i]*2); 186 | } 187 | else 188 | { 189 | strips[i] = 1; 190 | startIdx[i] = region.GetIndex()[i]+ totalErr[i]/2; 191 | } 192 | idx[i] = startIdx[i]; 193 | 194 | // with integer math keep track of the remaining odd pixel. 195 | // accErr/strips is the fractional pixels missing per superpixel 196 | // from even division. 197 | accErr[i] = totalErr[i]%(strips[i]*2); 198 | } 199 | 200 | 201 | const unsigned int numberOfComponents = inputImage->GetNumberOfComponentsPerPixel(); 202 | const unsigned int numberOfClusterComponents = numberOfComponents+ImageDimension; 203 | const size_t numberOfClusters = std::accumulate( &strips.m_Size[0], &strips.m_Size[0]+ImageDimension, size_t(1), std::multiplies() ); 204 | 205 | itkDebugMacro("numberOfClusters: " << numberOfClusters ); 206 | 207 | // allocate array of scalars 208 | std::vector(numberOfClusters*numberOfClusterComponents).swap(m_Clusters); 209 | std::vector(numberOfClusters*numberOfClusterComponents).swap(m_OldClusters); 210 | 211 | 212 | size_t cnt = 0; 213 | while( idx[ImageDimension-1] < region.GetUpperIndex()[ImageDimension-1] ) 214 | { 215 | 216 | 217 | for( SizeValueType i = 0; i < strips[0] - 1; ++i ) 218 | { 219 | RefClusterType cluster( numberOfClusterComponents, &m_Clusters[cnt*numberOfClusterComponents] ); 220 | ++cnt; 221 | 222 | CreateClusterPoint(inputImage->GetPixel(idx), 223 | cluster, 224 | numberOfComponents, 225 | idx ); 226 | itkDebugMacro("Initial cluster " << cnt-1 << " : " << cluster << " idx: " << idx ); 227 | accErr[0] += totalErr[0]; 228 | idx[0] += m_SuperGridSize[0] + accErr[0]/strips[0]; 229 | accErr[0] %= strips[0]; 230 | } 231 | 232 | RefClusterType cluster( numberOfClusterComponents, &m_Clusters[cnt*numberOfClusterComponents] ); 233 | ++cnt; 234 | 235 | CreateClusterPoint(inputImage->GetPixel(idx), 236 | cluster, 237 | numberOfComponents, 238 | idx ); 239 | itkDebugMacro("Initial cluster " << cnt-1<< " : " << cluster ); 240 | 241 | // increment the startIdx to next line on sample grid 242 | idx[0] = startIdx[0]; 243 | accErr[0] = totalErr[0]%(strips[0]*2); 244 | for ( unsigned int i = 1; i < ImageDimension; ++i ) 245 | { 246 | 247 | accErr[i] += totalErr[i]; 248 | idx[i] += m_SuperGridSize[0] + accErr[i]/strips[i]; 249 | accErr[i] %= strips[i]; 250 | 251 | if (idx[i] < region.GetUpperIndex()[i] 252 | || i == ImageDimension-1) 253 | { 254 | break; 255 | } 256 | idx[i] = startIdx[i]; 257 | accErr[i] = totalErr[i]%(strips[i]*2); 258 | } 259 | } 260 | 261 | itkDebugMacro("Initial Clustering Completed"); 262 | 263 | 264 | m_DistanceImage = DistanceImageType::New(); 265 | m_DistanceImage->CopyInformation(inputImage); 266 | m_DistanceImage->SetBufferedRegion( region ); 267 | m_DistanceImage->Allocate(); 268 | 269 | m_MarkerImage = ITK_NULLPTR; 270 | 271 | for (unsigned int i = 0; i < ImageDimension; ++i) 272 | { 273 | const double physicalGridSize = m_SuperGridSize[i]; 274 | m_DistanceScales[i] = 1.0/physicalGridSize; 275 | } 276 | 277 | 278 | m_UpdateClusterPerThread.resize(m_NumberOfThreadsUsed); 279 | std::vector >(m_NumberOfThreadsUsed).swap(m_MissedLabelsPerThread); 280 | 281 | this->Superclass::BeforeThreadedGenerateData(); 282 | } 283 | 284 | 285 | template 286 | void 287 | SLICImageFilter 288 | ::ThreadedUpdateDistanceAndLabel(const OutputImageRegionType & outputRegionForThread, ThreadIdType itkNotUsed(threadId)) 289 | { 290 | // This method modifies the OutputImage and the DistanceImage only 291 | // in the outputRegionForThread. It searches for any cluster, whose 292 | // search radius is within the output region for the thread. Then it 293 | // updates DistnaceImage with the minimum distance and the 294 | // corresponding label id in the output image. 295 | // 296 | typedef ImageScanlineConstIterator< InputImageType > InputConstIteratorType; 297 | typedef ImageScanlineIterator< DistanceImageType > DistanceIteratorType; 298 | 299 | const InputImageType *inputImage = this->GetInput(); 300 | OutputImageType *outputImage = this->GetOutput(); 301 | const unsigned int numberOfComponents = inputImage->GetNumberOfComponentsPerPixel(); 302 | const unsigned int numberOfClusterComponents = numberOfComponents+ImageDimension; 303 | 304 | typename InputImageType::SizeType searchRadius; 305 | for (unsigned int i = 0; i < ImageDimension; ++i) 306 | { 307 | searchRadius[i] = m_SuperGridSize[i]; 308 | } 309 | 310 | for (size_t i = 0; i*numberOfClusterComponents < m_Clusters.size(); ++i) 311 | { 312 | RefClusterType cluster(numberOfClusterComponents, &m_Clusters[i*numberOfClusterComponents]); 313 | typename InputImageType::RegionType localRegion; 314 | IndexType idx; 315 | 316 | for (unsigned int d = 0; d < ImageDimension; ++d) 317 | { 318 | idx[d] = Math::Round(cluster[numberOfComponents+d]); 319 | } 320 | 321 | localRegion.SetIndex(idx); 322 | localRegion.GetModifiableSize().Fill(1u); 323 | localRegion.PadByRadius(searchRadius); 324 | 325 | // Check cluster is in the output region for this thread. 326 | if (!localRegion.Crop(outputRegionForThread)) 327 | { 328 | continue; 329 | } 330 | 331 | 332 | const size_t ln = localRegion.GetSize(0); 333 | 334 | InputConstIteratorType inputIter(inputImage, localRegion); 335 | DistanceIteratorType distanceIter(m_DistanceImage, localRegion); 336 | 337 | 338 | while ( !inputIter.IsAtEnd() ) 339 | { 340 | for( size_t x = 0; x < ln; ++x ) 341 | { 342 | const IndexType ¤tIdx = inputIter.GetIndex(); 343 | 344 | const DistanceType distance = this->Distance(cluster, 345 | inputIter.Get(), 346 | currentIdx); 347 | if (distance < distanceIter.Get() ) 348 | { 349 | distanceIter.Set(distance); 350 | outputImage->SetPixel(currentIdx, static_cast(i)); 351 | } 352 | 353 | ++distanceIter; 354 | ++inputIter; 355 | } 356 | inputIter.NextLine(); 357 | distanceIter.NextLine(); 358 | } 359 | 360 | // for neighborhood iterator size S 361 | } 362 | 363 | } 364 | 365 | 366 | template 367 | void 368 | SLICImageFilter 369 | ::ThreadedUpdateClusters(const OutputImageRegionType & updateRegionForThread, ThreadIdType threadId) 370 | { 371 | const InputImageType *inputImage = this->GetInput(); 372 | OutputImageType *outputImage = this->GetOutput(); 373 | 374 | const unsigned int numberOfComponents = inputImage->GetNumberOfComponentsPerPixel(); 375 | const unsigned int numberOfClusterComponents = numberOfComponents+ImageDimension; 376 | 377 | typedef ImageScanlineConstIterator< InputImageType > InputConstIteratorType; 378 | typedef ImageScanlineIterator< OutputImageType > OutputIteratorType; 379 | 380 | UpdateClusterMap &clusterMap = m_UpdateClusterPerThread[threadId]; 381 | clusterMap.clear(); 382 | 383 | itkDebugMacro("Estimating Centers"); 384 | // calculate new centers 385 | OutputIteratorType itOut = OutputIteratorType(outputImage, updateRegionForThread); 386 | InputConstIteratorType itIn = InputConstIteratorType(inputImage, updateRegionForThread); 387 | ClusterType incr_cluster(numberOfClusterComponents); 388 | 389 | while(!itOut.IsAtEnd() ) 390 | { 391 | const size_t ln = updateRegionForThread.GetSize(0); 392 | for (size_t x = 0; x < ln; ++x) 393 | { 394 | const LabelPixelType l = itOut.Get(); 395 | 396 | std::pair r = clusterMap.insert(std::make_pair(l,UpdateCluster())); 397 | ClusterType &cluster = r.first->second.cluster; 398 | if (r.second) 399 | { 400 | cluster.set_size(numberOfClusterComponents); 401 | cluster.fill(0.0); 402 | r.first->second.count = 0; 403 | } 404 | ++r.first->second.count; 405 | 406 | // create cluster point 407 | CreateClusterPoint(itIn.Get(), 408 | incr_cluster, 409 | numberOfComponents, 410 | itOut.GetIndex() ); 411 | 412 | cluster += incr_cluster; 413 | 414 | ++itIn; 415 | ++itOut; 416 | } 417 | itIn.NextLine(); 418 | itOut.NextLine(); 419 | } 420 | } 421 | 422 | 423 | template 424 | void 425 | SLICImageFilter 426 | ::ThreadedPerturbClusters(const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId ) 427 | { 428 | // Update the m_Clusters array by spiting the threads over the 429 | // cluster indexes, moving cluster center to the 430 | // lowest gradient position in a 1-radius neighborhood. 431 | 432 | const InputImageType *inputImage = this->GetInput(); 433 | 434 | const unsigned int numberOfComponents = inputImage->GetNumberOfComponentsPerPixel(); 435 | const unsigned int numberOfClusterComponents = numberOfComponents+ImageDimension; 436 | const size_t numberOfClusters = m_Clusters.size()/numberOfClusterComponents; 437 | 438 | itk::Size radius; 439 | radius.Fill( 1 ); 440 | unsigned long center; 441 | unsigned long stride[ImageDimension]; 442 | 443 | 444 | typename InputImageType::SizeType searchRadius; 445 | searchRadius.Fill(1); 446 | 447 | 448 | typedef ConstNeighborhoodIterator< TInputImage > NeighborhoodType; 449 | 450 | // get center and dimension strides for iterator neighborhoods 451 | NeighborhoodType it( radius, inputImage, outputRegionForThread); 452 | center = it.Size()/2; 453 | for ( unsigned int i = 0; i < ImageDimension; ++i ) 454 | { 455 | stride[i] = it.GetStride(i); 456 | } 457 | 458 | const typename InputImageType::SpacingType spacing = inputImage->GetSpacing(); 459 | 460 | // ceiling of number of clusters divided by actual number of threads 461 | const size_t strideCluster = 1 + ((numberOfClusters - 1) / m_NumberOfThreadsUsed); 462 | size_t clusterIndex = strideCluster*threadId; 463 | const size_t stopCluster = std::min(numberOfClusters, clusterIndex+strideCluster); 464 | 465 | for (; clusterIndex < stopCluster; ++clusterIndex) 466 | { 467 | // cluster is a reference to array 468 | RefClusterType cluster(numberOfClusterComponents, &m_Clusters[clusterIndex*numberOfClusterComponents]); 469 | typename InputImageType::RegionType localRegion; 470 | IndexType idx; 471 | 472 | for (unsigned int d = 0; d < ImageDimension; ++d) 473 | { 474 | idx[d] = Math::Round(cluster[numberOfComponents+d]); 475 | } 476 | 477 | localRegion.SetIndex(idx); 478 | localRegion.GetModifiableSize().Fill(1u); 479 | localRegion.PadByRadius(searchRadius); 480 | 481 | it.SetRegion( localRegion ); 482 | 483 | double minG = NumericTraits::max(); 484 | 485 | IndexType minIdx = idx; 486 | 487 | double gNorm; 488 | vnl_vector A(numberOfComponents), B(numberOfComponents); 489 | 490 | while ( !it.IsAtEnd() ) 491 | { 492 | 493 | // Use the 1-norm of the Jacobian for the "Gradient Magnitude" 494 | // of single or multi-component images. 495 | gNorm = 0; 496 | for ( unsigned int i = 0; i < ImageDimension; i++ ) 497 | { 498 | NumericTraits::AssignToArray(it.GetPixel(center + stride[i]), A); 499 | NumericTraits::AssignToArray(it.GetPixel(center - stride[i]), B); 500 | A -= B; 501 | A /= spacing[i]; // omitting constant 2 502 | gNorm += A.one_norm(); 503 | } 504 | 505 | if ( gNorm < minG) 506 | { 507 | minG = gNorm; 508 | minIdx = it.GetIndex(); 509 | } 510 | ++it; 511 | } 512 | 513 | // create cluster point 514 | CreateClusterPoint(inputImage->GetPixel(minIdx), 515 | cluster, 516 | numberOfComponents, 517 | minIdx ); 518 | 519 | } 520 | 521 | } 522 | 523 | 524 | template 525 | void 526 | SLICImageFilter 527 | ::ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId) 528 | { 529 | const InputImageType *inputImage = this->GetInput(); 530 | 531 | const typename InputImageType::RegionType region = inputImage->GetBufferedRegion(); 532 | const unsigned int numberOfComponents = inputImage->GetNumberOfComponentsPerPixel(); 533 | const unsigned int numberOfClusterComponents = numberOfComponents+ImageDimension; 534 | 535 | itkDebugMacro("Perturb cluster centers"); 536 | ThreadedPerturbClusters(outputRegionForThread,threadId); 537 | 538 | itkDebugMacro("Entering Main Loop"); 539 | for(unsigned int loopCnt = 0; loopCntFillBuffer(NumericTraits::max()); 546 | } 547 | m_Barrier->Wait(); 548 | 549 | ThreadedUpdateDistanceAndLabel(outputRegionForThread,threadId); 550 | 551 | m_Barrier->Wait(); 552 | 553 | 554 | ThreadedUpdateClusters(outputRegionForThread, threadId); 555 | 556 | m_Barrier->Wait(); 557 | 558 | if (threadId==0) 559 | { 560 | // prepare to update clusters 561 | swap(m_Clusters, m_OldClusters); 562 | std::fill(m_Clusters.begin(), m_Clusters.end(), 0.0); 563 | std::vector clusterCount(m_Clusters.size()/numberOfClusterComponents, 0); 564 | 565 | // reduce the produce cluster maps per-thread into m_Cluster array 566 | for(size_t i = 0; i < m_UpdateClusterPerThread.size(); ++i) 567 | { 568 | const UpdateClusterMap &clusterMap = m_UpdateClusterPerThread[i]; 569 | for(typename UpdateClusterMap::const_iterator clusterIter = clusterMap.begin(); clusterIter != clusterMap.end(); ++clusterIter) 570 | { 571 | const size_t clusterIdx = clusterIter->first; 572 | clusterCount[clusterIdx] += clusterIter->second.count; 573 | 574 | RefClusterType cluster(numberOfClusterComponents, &m_Clusters[clusterIdx*numberOfClusterComponents]); 575 | cluster += clusterIter->second.cluster; 576 | } 577 | } 578 | 579 | // average 580 | for (size_t i = 0; i*numberOfClusterComponents < m_Clusters.size(); ++i) 581 | { 582 | if (clusterCount[i] != 0) 583 | { 584 | RefClusterType cluster(numberOfClusterComponents,&m_Clusters[i*numberOfClusterComponents]); 585 | cluster /= clusterCount[i]; 586 | } 587 | } 588 | 589 | // residual 590 | #if !defined NDEBUG 591 | double l1Residual = 0.0; 592 | for (size_t i = 0; i*numberOfClusterComponents < m_Clusters.size(); ++i) 593 | { 594 | 595 | const RefClusterType cluster(numberOfClusterComponents,&m_Clusters[i*numberOfClusterComponents]); 596 | const RefClusterType oldCluster(numberOfClusterComponents, &m_OldClusters[i*numberOfClusterComponents]); 597 | l1Residual += Distance(cluster,oldCluster); 598 | } 599 | itkDebugMacro( << "L1 residual: " << std::sqrt(l1Residual) ); 600 | #endif 601 | } 602 | // while error <= threshold 603 | } 604 | 605 | if(m_LabelConnectivityEnforce && !m_LabelConnectivityRelabelSequential) 606 | { 607 | 608 | m_Barrier->Wait(); 609 | if (threadId == 0) 610 | { 611 | m_DistanceImage = ITK_NULLPTR; 612 | 613 | m_MarkerImage = MarkerImageType::New(); 614 | m_MarkerImage->CopyInformation(inputImage); 615 | m_MarkerImage->SetBufferedRegion( region ); 616 | m_MarkerImage->Allocate(); 617 | m_MarkerImage->FillBuffer(-2); 618 | } 619 | m_Barrier->Wait(); 620 | 621 | const size_t superGirdArea = 622 | std::accumulate( &m_SuperGridSize[0], 623 | &m_SuperGridSize[0]+ImageDimension, size_t(1), 624 | std::multiplies() ); 625 | 626 | // Split the clusters up over threads, updating m_Marker map 627 | // with visited regions, centered and connected with the cluster 628 | 629 | // ceiling of number of clusters divided by actual number of threads 630 | const size_t numberOfClusters = m_Clusters.size() / numberOfClusterComponents; 631 | const size_t stride = 1 + ((numberOfClusters - 1) / m_NumberOfThreadsUsed ); 632 | 633 | 634 | std::list &missedLabels = this->m_MissedLabelsPerThread[threadId]; 635 | 636 | size_t i = stride*threadId; 637 | const size_t stopCluster = std::min(numberOfClusters, i+stride); 638 | 639 | for (; i < stopCluster; ++i) 640 | { 641 | RefClusterType cluster(numberOfClusterComponents,&m_Clusters[i*numberOfClusterComponents]); 642 | IndexType idx; 643 | 644 | for (unsigned int d = 0; d < ImageDimension; ++d) 645 | { 646 | idx[d] = Math::Round(cluster[numberOfComponents+d]); 647 | } 648 | 649 | // count 650 | const size_t count = this->RelabelClusterAndMark(idx, i, -1); 651 | 652 | if ( count > m_LabelConnectivityMinimumSize*superGirdArea ) 653 | { 654 | this->RelabelClusterAndMark(idx, i, 1, i); 655 | } 656 | else 657 | { 658 | missedLabels.push_back(i); 659 | } 660 | } 661 | 662 | } 663 | 664 | 665 | } 666 | 667 | template 668 | size_t 669 | SLICImageFilter 670 | ::RelabelClusterAndMark(const IndexType &idx, 671 | LabelPixelType label, 672 | MarkerPixelType relabel, 673 | LabelPixelType outLabel ) 674 | { 675 | 676 | OutputImageType *outputImage = this->GetOutput(); 677 | 678 | std::vector idxStack; 679 | // todo reserve 680 | 681 | const typename OutputImageType::RegionType region = outputImage->GetBufferedRegion(); 682 | 683 | size_t count = 0; 684 | IndexType tempIdx = idx; 685 | if ( m_MarkerImage->GetPixel(tempIdx) < relabel 686 | && outputImage->GetPixel(tempIdx) == label) 687 | { 688 | ++count; 689 | m_MarkerImage->SetPixel(tempIdx, relabel); 690 | idxStack.push_back(tempIdx); 691 | if (relabel > 0) 692 | { 693 | outputImage->SetPixel(tempIdx, outLabel); 694 | } 695 | } 696 | 697 | while( !idxStack.empty() ) 698 | { 699 | tempIdx = idxStack.back(); 700 | idxStack.pop_back(); 701 | 702 | for ( unsigned int i = 0; i < ImageDimension; i++ ) 703 | { 704 | for ( int j = -1; j <= 1; j += 2 ) 705 | { 706 | tempIdx[i] += j; 707 | if (region.IsInside(tempIdx)) 708 | { 709 | LabelPixelType &currLabel = outputImage->GetPixel(tempIdx); 710 | if (currLabel == label 711 | && m_MarkerImage->GetPixel(tempIdx) < relabel ) 712 | { 713 | ++count; 714 | m_MarkerImage->SetPixel(tempIdx, relabel); 715 | idxStack.push_back(tempIdx); 716 | if (relabel > 0) 717 | { 718 | currLabel = outLabel; 719 | } 720 | } 721 | 722 | } 723 | tempIdx[i] -= j; 724 | } 725 | } 726 | } 727 | return count; 728 | } 729 | 730 | template 731 | void 732 | SLICImageFilter 733 | ::AfterThreadedGenerateData() 734 | { 735 | 736 | itkDebugMacro("Starting AfterThreadedGenerateData"); 737 | 738 | m_DistanceImage = ITK_NULLPTR; 739 | 740 | const InputImageType *inputImage = this->GetInput(); 741 | OutputImageType *outputImage = this->GetOutput(); 742 | 743 | const typename OutputImageType::RegionType region = outputImage->GetBufferedRegion(); 744 | 745 | if (m_LabelConnectivityEnforce) 746 | { 747 | 748 | if (!m_MarkerImage) 749 | { 750 | m_MarkerImage = MarkerImageType::New(); 751 | m_MarkerImage->CopyInformation(inputImage); 752 | m_MarkerImage->SetBufferedRegion( region ); 753 | m_MarkerImage->Allocate(); 754 | } 755 | 756 | const size_t superGirdArea = 757 | std::accumulate( &m_SuperGridSize[0], 758 | &m_SuperGridSize[0]+ImageDimension, size_t(1), 759 | std::multiplies() ); 760 | 761 | 762 | std::list missedLabels; 763 | if (m_LabelConnectivityRelabelSequential) 764 | { 765 | missedLabels.push_back(0); 766 | m_MarkerImage->FillBuffer(-1); 767 | } 768 | else 769 | { 770 | // merge missing labels, from threaded initial labeling 771 | for (typename std::vector >::iterator i = m_MissedLabelsPerThread.begin(); 772 | i != m_MissedLabelsPerThread.end(); 773 | ++i) 774 | { 775 | missedLabels.splice(missedLabels.end(), *i); 776 | } 777 | const unsigned int numberOfComponents = inputImage->GetNumberOfComponentsPerPixel(); 778 | const unsigned int numberOfClusterComponents = numberOfComponents+ImageDimension; 779 | const LabelPixelType numberOfClusters = static_cast(m_Clusters.size() / numberOfClusterComponents); 780 | missedLabels.push_back(numberOfClusters); 781 | } 782 | 783 | typedef ImageScanlineIterator< OutputImageType > OutputIteratorType; 784 | typedef ImageScanlineConstIterator< MarkerImageType > MarkerIteratorType; 785 | 786 | 787 | OutputIteratorType outputIter(outputImage, region); 788 | MarkerIteratorType markerIter(m_MarkerImage, region); 789 | const size_t ln = region.GetSize(0); 790 | 791 | // the next label to use for relabeling 792 | LabelPixelType nextLabel = missedLabels.front(); 793 | missedLabels.pop_front(); 794 | 795 | while ( !outputIter.IsAtEnd() ) 796 | { 797 | for( size_t x = 0; x < ln; ++x ) 798 | { 799 | if ( markerIter.Get() == 0 ) 800 | { 801 | std::cout << "unexpected 0 mark @ " << markerIter.GetIndex() << " label: " << outputIter.Get() << std::endl; 802 | } 803 | if ( markerIter.Get() < 0) 804 | { 805 | const LabelPixelType currLabel = outputIter.Get(); 806 | 807 | const size_t countLabel = this->RelabelClusterAndMark(outputIter.GetIndex(), currLabel, 0); 808 | 809 | if (countLabel < m_LabelConnectivityMinimumSize*superGirdArea) 810 | { 811 | 812 | LabelPixelType replaceLabel = 0; 813 | IndexType tempIdx = outputIter.GetIndex(); 814 | for ( unsigned int i = 0; i < ImageDimension; i++ ) 815 | { 816 | for ( int j = -1; j <= 1; j += 2 ) 817 | { 818 | tempIdx[i] += j; 819 | if (region.IsInside(tempIdx)) 820 | { 821 | const LabelPixelType l = outputImage->GetPixel(tempIdx); 822 | if (m_MarkerImage->GetPixel(tempIdx) > 0) 823 | { 824 | replaceLabel = l; 825 | } 826 | } 827 | tempIdx[i] -= j; 828 | } 829 | } 830 | 831 | itkDebugMacro("Replacing island with neighbor: " << outputIter.Get() << "->" << replaceLabel<< " " << outputIter.GetIndex()); 832 | this->RelabelClusterAndMark(outputIter.GetIndex(), currLabel, 1, replaceLabel); 833 | } 834 | else 835 | { 836 | 837 | itkDebugMacro("Relabling big island of: " << outputIter.Get() << " with new label: " << outputIter.Get() << "->" << nextLabel); 838 | this->RelabelClusterAndMark(outputIter.GetIndex(), currLabel, 1, nextLabel); 839 | 840 | if ( nextLabel != NumericTraits::max() ) 841 | { 842 | if (!missedLabels.empty()) 843 | { 844 | nextLabel = missedLabels.front(); 845 | missedLabels.pop_front(); 846 | } 847 | else 848 | { 849 | ++nextLabel; 850 | } 851 | } 852 | } 853 | 854 | } 855 | ++outputIter; 856 | ++markerIter; 857 | } 858 | outputIter.NextLine(); 859 | markerIter.NextLine(); 860 | } 861 | } 862 | 863 | // Clean up all algorithm variables 864 | m_MarkerImage = ITK_NULLPTR; 865 | 866 | // cleanup 867 | std::vector().swap(m_Clusters); 868 | std::vector().swap(m_OldClusters); 869 | std::vector >().swap(m_MissedLabelsPerThread); 870 | for(unsigned int i = 0; i < m_UpdateClusterPerThread.size(); ++i) 871 | { 872 | UpdateClusterMap().swap(m_UpdateClusterPerThread[i]); 873 | } 874 | } 875 | 876 | 877 | template 878 | typename SLICImageFilter::DistanceType 879 | SLICImageFilter 880 | ::Distance(const ClusterType &cluster1, const ClusterType &cluster2) 881 | { 882 | const unsigned int s = cluster1.size(); 883 | double d1 = 0.0; 884 | double d2 = 0.0; 885 | unsigned int i = 0; 886 | for (; i